103

I'm new to using JAXB, and I used JAXB 2.1.3's xjc to generate a set of classes from my XML Schema. In addition to generating a class for each element in my schema, it created an ObjectFactory class.

There doesn't seem to be anything stopping me from instantiating the elements directly, e.g.

MyElement element = new MyElement();

whereas tutorials seem to prefer

MyElement element = new ObjectFactory().createMyElement();

If I look into ObjectFactory.java, I see:

public MyElement createMyElement() {
    return new MyElement();
}

so what's the deal? Why should I even bother keeping the ObjectFactory class around? I assume it will also be overwritten if I were to re-compile from an altered schema.

Andrew Coleson
  • 10,100
  • 8
  • 32
  • 30
  • I'm not sure if it's intended design, but I've found ObjectFactory an ideal class to use for JAXBContext creation. You need to enumerate some classes there and JAXB will follow on their methods, etc, so they are something like roots. And ObjectFactory has references to all elements, so it's enough to just use ObjectFactory.class to create JAXBContext with all relevant classes. – vbezhenar Jun 07 '19 at 09:41

3 Answers3

72

Backward compatibility isn't the only reason. :-P

With more complicated schemas, such as ones that have complicated constraints on the values that an element's contents can take on, sometimes you need to create actual JAXBElement objects. They are not usually trivial to create by hand, so the create* methods do the hard work for you. Example (from the XHTML 1.1 schema):

@XmlElementDecl(namespace = "http://www.w3.org/1999/xhtml", name = "style", scope = XhtmlHeadType.class)
public JAXBElement<XhtmlStyleType> createXhtmlHeadTypeStyle(XhtmlStyleType value) {
    return new JAXBElement<XhtmlStyleType>(_XhtmlHeadTypeStyle_QNAME, XhtmlStyleType.class, XhtmlHeadType.class, value);
}

This is how you get a <style> tag into a <head> tag:

ObjectFactory factory = new ObjectFactory();
XhtmlHtmlType html = factory.createXhtmlHtmlType();
XhtmlHeadType head = factory.createXhtmlHeadType();
html.setHead(head);
XhtmlStyleType style = factory.createXhtmlStyleType();
head.getContent().add(factory.createXhtmlHeadTypeStyle(style));

The first three uses of the ObjectFactory could be considered superfluous (though useful for consistency), but the fourth one makes JAXB much, much easier to use. Imaging having to write a new JAXBElement out by hand each time!

C. K. Young
  • 219,335
  • 46
  • 382
  • 435
  • Can you give an example/reference of what (or how complicated) a Schema element needs to be in order for create*() to do something useful? I'm having trouble finding the part of the Schema you're referencing with your JAXB example. If my Schema gets more complicated later, it'd certainly be nice for create* to handle part of it for me, but as it is create* doesn't even bother creating sub-elements on its own.. – Andrew Coleson Jun 05 '09 at 15:06
  • If you download the XHTML 1.1 and XHTML Modularization 1.1 tarballs, you will find directories inside called "SCHEMA". Put all the .xsd files in the same directories. Some of the .xsd files will also import http://www.w3.org/2001/xml.xsd; you will want to adjust the locations appropriately if you don't want the file downloaded each time you run xjc. [cont] – C. K. Young Jun 05 '09 at 19:41
  • [cont] The specific part of the .xsd that specifies the content of a is, in this case, in xhtml11-model-1.xsd, under the xhtml.head.content group. – C. K. Young Jun 05 '09 at 19:43
  • 2
    In any case, nobody is pointing a gun to your head saying you must use ObjectFactory (although I find it handy to use), but when you come across a case where it's genuinely useful, you will know it. :-) – C. K. Young Jun 05 '09 at 19:44
  • Thanks! I guess my schema's just not complicated enough, but I'll keep it in mind for the future. :) I knew I had to be missing something. – Andrew Coleson Jun 06 '09 at 17:54
  • is there a way to suppress creating ObjectFactory? i use a xjc plugin to generate customized code. and i have no way of suppressing ObjectFactory creatiopn from the plugin. is there an option to suppress it – weima Oct 07 '15 at 14:44
  • @weima If you don't want to use it, just don't use it. There are some things, as mentioned in my answer, that you can't easily do without an `ObjectFactory`, so suppressing its generation is not something people generally want to do. – C. K. Young Oct 07 '15 at 14:46
41

As @Chris pointed out, sometimes JAXB cannot work with POJOs, because the schema cannot be mapped exactly on to Java. In these cases, JAXBElement wrapper objects are necessary to provide the additional type information.

There are two concrete examples that I've come across where this is common.

  • If you want to marshal an object of a class that does not have the @XmlRootElement annotation. By default XJC only generates @XmlRootElement for some elements, and not for others. The exact logic for this is a bit complicated, but you can force XJC to generate more @XmlRootElement classes using the "simple binding mode"

  • When your schema uses substituion groups. This is pretty advanced schema usage, but XJC translates substitution groups into Java by making heavy use of JAXBElement wrappers.

So in an XJC-generated object model which makes heavy use of JAXBElement (for whatever reason), you need a way of constructing those JAXBElement instances. The generated ObjectFactory is by far the easiest way to do it. You can construct them yourself, but it's clunky and error-prone to do so.

skaffman
  • 398,947
  • 96
  • 818
  • 769
9

Backwards compatibility, I guess ...

http://weblogs.java.net/blog/kohsuke/archive/2005/08/a_story_of_migr.html:

...No more ObjectFactory.createXYZ. The problem with those factory methods was that they throw a checked JAXBException. Now you can simply do new XYZ(), no more try/catch blocks. (I know, I know, ... this is one of those "what were we thinking!?" things)...

skaffman
  • 398,947
  • 96
  • 818
  • 769
Bert F
  • 85,407
  • 12
  • 106
  • 123