I have defined the following ObjectFactory
:
@XmlRegistry
public class ObjectFactory {
public Dogs createDogs() {
return new Dogs();
The short answer is because the factory methods are not generated into the @XmlType
annotation to tell JAXB to do so:
@XmlRootElement(name = "listOfDogs")
@XmlType(factoryClass=ObjectFactory.class, factoryMethod="createDogs") // not generated
public class Dogs {
Shouldn't it be? Or is ist just a dummy to hold the @XmlRegistry/@XmlElementDecl declarations?
In my opinion yes it should be used to instantiate the classes.
ObjectFactory
is a throw back to JAXB 1.0. In JAXB 1.0 the spec defined what the generated interfaces looked like and implementations could back those generated interfaces with what ever impl they wanted to provide. Back then you needed to use the ObjectFactory
class to create your model in a vendor independent way.
JAXB 2.0 switched to a POJO model where you were free to use the default constructor. If JAXB 1.0 had never existed would there be an ObjectFactory
class, that's hard to tell. Since it previously existed the ObjectFactory
class was kept for a couple of reasons:
@XmlElementDecl
. The @XmlRegistry
annotation is really just a marker annotation used to indicate the class that contains the @XmlElementDecl
annotations without restricting it to a class called ObjectFactory
.Your use case may be able to be achieved with an XmlAdapter
, although its not clear to me what logic you are trying to have in the ObjectFactory
.
XmlAdapter (DogAdapter)
Your custom logic goes on the XmlAdapter
.
import javax.xml.bind.*;
import javax.xml.bind.annotation.adapters.*;
public class DogAdapter extends XmlAdapter<JAXBElement<DogType>, JAXBElement<DogType>> {
@Override
public JAXBElement<DogType> unmarshal(JAXBElement<DogType> v) throws Exception {
return new Dog(v.getName().getLocalPart(), v.getValue());
}
@Override
public JAXBElement<DogType> marshal(JAXBElement<DogType> v) throws Exception {
return v;
}
}
Dogs
The XmlAdapter
is referenced from the @XmlJavaTypeAdapter
annotation.
import java.util.*;
import javax.xml.bind.*;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlRootElement(name = "listOfDogs")
public class Dogs {
private List<JAXBElement<DogType>> dogs = new LinkedList<JAXBElement<DogType>>();
@XmlElementWrapper(name = "dogs")
@XmlElementRef(name = "dog")
@XmlJavaTypeAdapter(DogAdapter.class)
public List<JAXBElement<DogType>> getDogs() {
return this.dogs;
}
@Override
public String toString() {
return "Dogs [dogs=" + dogs + "]";
}
}
ObjectFactory
ObjectFactory
is now a dumb class that just holds the @XmlElementDecl
annotations:
import javax.xml.bind.*;
import javax.xml.bind.annotation.*;
import javax.xml.namespace.QName;
@XmlRegistry
public class ObjectFactory {
public Dogs createDogs() {
return new Dogs();
}
@XmlElementDecl(name = "dog")
public JAXBElement<DogType> createDog(DogType value) {
return new Dog(value);
}
@XmlElementDecl(name = "fido", substitutionHeadName = "dog", substitutionHeadNamespace = "")
public JAXBElement<DogType> createFido(DogType value) {
return new JAXBElement<DogType>(new QName("fido"), DogType.class, value);
}
@XmlElementDecl(name = "barks", substitutionHeadName = "dog", substitutionHeadNamespace = "")
public JAXBElement<DogType> createBarks(DogType value) {
return new JAXBElement<DogType>(new QName("barks"), DogType.class, value);
}
}
My question, however is more about the specification. According to the spec, should the create* methods from the ObjectFactory be executed or not?
In JAXB 2 there is no difference in a model created from scratch versus one generated from an XML Schema. As such you need to look to the spec at what it says about classes. According to what is reference below it comes down to no-arg constructor or a specified factory method.
From section 8.7.1.2 Mapping of the JAXB 2.2 (JSR-222) specification:
a class must have a public or protected no-arg constructor or a factory method identified by {factoryClass(), factoryMethod()} unless it is adapted using @XmlJavaTypeAdapter.