While JAXB is a good method of mapping XML into Java objects, if your schema’s are large or complex, generating the required Object graph prior to marshaling into XML can be both tedious and error prone due to the large amount of ‘boiler plate’ code of creating an object, calling accessor methods to set the values etc.
A common pattern for easing this sort of thing is known as the Builder pattern where you either have a common object holding configuration and then it builds the objects for you, or a set of objects each configured with the information and when required then build the final Object graph.
Previously however, this involved writing these builder classes manually once you have generated the model from a schema, however retepTools provides a JAXB plugin which, with a little configuration within the bindings will automatically generate these builders for you.
First an example of a simple pair of objects to be generated by JAXB – this is an abridged version of the jabber:client namespace in XMPP:
<?xml version='1.0' encoding='UTF-8'?> <xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema' targetNamespace='jabber:client' xmlns='jabber:client' elementFormDefault='qualified'> <xs:element name='message'> <xs:complexType> <xs:sequence> <xs:choice minOccurs='0' maxOccurs='unbounded'> <xs:element ref='subject'/> <xs:element ref='body'/> </xs:choice> </xs:sequence> <xs:attribute name='from' type='xs:string' use='optional'/> <xs:attribute name='from' type='xs:string' use='optional'/> </xs:complexType> </xs:element> <xs:element name='body'> <xs:complexType> <xs:simpleContent> <xs:extension base='nonEmptyString'> <xs:attribute ref='xml:lang' use='optional'/> </xs:extension> </xs:simpleContent> </xs:complexType> </xs:element> <xs:element name='subject'> <xs:complexType> <xs:simpleContent> <xs:extension base='nonEmptyString'> <xs:attribute ref='xml:lang' use='optional'/> </xs:extension> </xs:simpleContent> </xs:complexType> </xs:element> <xs:simpleType name='nonEmptyString'> <xs:restriction base='xs:string'> <xs:minLength value='1'/> </xs:restriction> </xs:simpleType> </xs:schema>
Now if run through JAXB this would generate three classes: Message, Body and Subject. With this default model you would have to do something like the following to create a valid Message:
Message message = new Message(); message.setFrom( "email@example.com/balcony" ); message.setTo( "firstname.lastname@example.org" ); Body body = new Body(); body.getBodyOrSubject().add( "Wherefore art thou, Romeo?" ); message.setBody( body );
Now with this simple example thats fine, but imagine something where your model is far more complex, or worse can contain arbitary namespaces as children such as in XMPP where Message can contain objects within any namespace?
This is where Builders become useful. Imagine the above being converted into this:
Message message = new MessageBuilder(). setFrom( "email@example.com/balcony" ). setTo( "firstname.lastname@example.org" ). addBody( new BodyBuilder(). setValue( "Wherefore art thou, Romeo?") ). build();
Although at first this may look similar to the standard way, the builders break the code into more manageable chunks. The builders themselves can be reused, so if you are sending multiple messages then you could change the above code to:
MessageBuilder builder = new MessageBuilder(). setFrom( "email@example.com/balcony" ). addBody( new BodyBuilder(). setValue( "Wherefore art thou, Romeo?") ); Message message1 = builder.setTo( "firstname.lastname@example.org" ).build(); Message message2 = builder.setTo( "email@example.com/cousin" ).build();
As you can see, the use of builders becomes apparent, we created two Message objects with a single change between them in a lot less code.
On the next page we’ll configure maven to build these builders.
3 thoughts on “Implementing Builders with JAXB generated objects”
This looks really cool. I am having some trouble getting it working – any idea what it means when it says:
“[ERROR] compiler was unable to honor this retep:builder customization. It is attached to a wrong place, or its inconsistent with other bindings.”?
I’ve got basically the same setup as what you have here.
Looks great, until you reach the point of defining binding for *each* complexType
You make a great case for builders and how its better to generate them straight from the schema rather than manually extend classes. Is retepTools still active/functional with a semi-latest version of maven-jaxb2-plugin from 2013?