Object Model Factory
Here is the definition of the ObjectModelFactory interface
package org.jboss.xml.binding; public interface ObjectModelFactory { /** * This method is called by the object model factory and returns the root of the object graph. * If the <code>root</code> argument is null the factory is supposed to create and return a new one. * If the <code>root</code> argument is not null (i.e. the user provided the root object through the * org.jboss.xml.binding.Unmarshaller) then the factory should either just return it as is * or extract the real root from the <code>root</code> argument based on the namespace URI and local name. * * @param root an object that is the root or which contains the root object * @param navigator content navigator * @param namespaceURI namespace URI of the root * @param localName local name of the root * @param attrs attributes of the root object * @return the root of the object graph */ Object newRoot(java.lang.Object root, org.jboss.xml.binding.ContentNavigator navigator, java.lang.String namespaceURI, java.lang.String localName, org.xml.sax.Attributes attrs); }
All object model factories must implement this interface.
Besides, the newRoot method defined in the ObjectModelFactory interface an object model factory should also implement a set of the following methods that will be discovered by the framework with introspection:
a set of newChild
methods
This method is called on the object model factory by the framework when parsing of a new XML element started.
Each
newChild
method must have five arguments:
parent object of a concrete Java type (not java.lang.Object) for this new child
instance of org.jboss.xml.binding.ContentNavigator
namespace URI of the child XML element as java.lang.String
local name of the child XML element as java.lang.String
attributes of the child XML element as org.xml.sax.Attributes
Each
newChild
method returns either a new instance of an object that represents the XML element with the namespace URI and local name (in this case, the child XML element is accepted, i.e. should be represented in the object graph) or
null
if this child XML element should be ignored, i.e. not be represented in the object graph.
a set of addChild
methods
This method is called on the object model factory by the framework when parsing of a child XML element is complete.
Each
addChild
method must have five arguments:
parent object of a conrete Java type (not java.lang.Object) of the child
child object of a concrete Java type (returned earlier by the
newChild()
)
instance of org.jboss.xml.binding.ContentNavigator
namespace URI for the child XML element as java.lang.String
local name for the child XML element as java.lang.String
When
addChild
method is called, the child object is supposed to be populated with all the data from the corresponding XML element. The child object now can be validated and added to the parent.
a set of setValue
methods
This method is called on the object model factory by the framework when a new XML element with text content was parsed.
The method must have four arguments:
an object of a concrete Java type (not java.lang.Object) which was returned earlier by a
newChild
for which the value of an XML element was read
instance of org.jboss.xml.binding.ContentNavigator
namespace URI of the child XML element as java.lang.String
local name of the child XML element as java.lang.String
the value of the child XML element as java.lang.String
In
setValue
method the object model factory is supposed to set a value on the field which represents the parsed XML element possibly converting the parsed XML element value to field's Java type.
Code example
Let's now implement
ObjectModelFactory
for book following the rules above.
public class BookObjectFactory implements org.jboss.xml.binding.ObjectModelFactory { // ObjectModelFactory implementation /** * Return the root. */ public Object newRoot(Object root, ContentNavigator navigator, String namespaceURI, String localName, Attributes attrs) { final Book book; if(root == null) { root = book = new Book(); } else { book = (Book) root; } if(attrs.getLength() > 0) { for(int i = 0; i < attrs.getLength(); ++i) { if(attrs.getLocalName(i).equals("isbn")) { book.setIsbn(attrs.getValue(i)); } } } return root; } // Methods discovered by introspection /** * Called when a child element with text content is read for book. */ public void setValue(Book book, ContentNavigator navigator, String namespaceURI, String localName, String value) { if("title".equals(localName)) { book.setTitle(value); } else if("author".equals(localName)) { book.setAuthor(value); } } /** * Called when parsing of a new child XML element started. */ public Object newChild(Book book, ContentNavigator navigator, String namespaceURI, String localName, Attributes attrs) { Object child = null; if("character".equals(localName)) { child = new BookCharacter(); } return child; } /** * Called when a child XML element with text content is read for character. */ public void setValue(BookCharacter character, ContentNavigator navigator, String namespaceURI, String localName, String value) { if("name".equals(localName)) { character.setName(value); } else if("friend-of".equals(localName)) { character.setFriendOf(value); } else if("since".equals(localName)) { character.setSince(value); } else if("qualification".equals(localName)) { character.setQualification(value); } } /** * Called when parsing character is complete. */ public void addChild(Book book, BookCharacter character, ContentNavigator navigator) { book.addCharacter(character); } }
Unmarshalling client
Now, having Java classes and object model factory we can write a client code.
// get the XML stream InputStream is = new FileInputStream("resources/xml/book/" + xmlSource); // create unmarshaller Unmarshaller unmarshaller = new Unmarshaller(); // create an instance of ObjectModelFactory ObjectModelFactory factory = new BookObjectFactory(); // let the object model factory to create an instance of Book and populate it with data from XML Book book = (Book)unmarshaller.unmarshal(is, factory, null); // close the XML stream is.close();
To unmarshal into an existing instance of
Book
, we would just pass the book instance as the third parameter to
Unmarshaller.unmarshal()
, e.g.
Book book = new Book(); unmarshaller.unmarshal(is, factory, book);
That's it!
Note, unmarshalling code is aware of neither XML schemas nor DTDs. XML schemas and DTDs are used transparently to the client by the underlying XML parser for XML content validation.
See also, GenericObjectModelFactory.
Comments