Survey
* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project
Java-XML binding approaches
@ Apache
© 2005 Thomas Dudziak
tomdz@apache.org
What’s in it
Binding approaches
Short detour: XML Schema
The sample schema & data
The tools
JAXB, JaxMe, XMLBeans
XStream
JiBX, commons-betwixt
A few notes about performance
How to choose the right approach
Binding ?
Java apps deal with data in XML
But SAX/DOM is tedious
Java <-> XML binding to the rescue
It handles converting between Java objects
and XML entities for you
It‘s not that easy, of course …
What we have and what we want
Several binding approaches are available
Document vs. model centric
Which one is good depends on what you
start with:
XML, possibly even with a fixed Schema
Java model classes
Functional and technical constraints
Worst case: fixed XML schema and fixed
Java classes
Binding approaches
Document centric
Schema Java compilers
Extension of the Java language
Model centric
XML Serialization
Java Schema compilers
Mixed
Java – XML Mapping
The presented tools
Java Schema compilers
JAXB RI & JAXB 2 RI
JaxMe 2
XMLBeans
XML Serialization
XStream
Mapping
JiBX
Commons-betwixt
Detour: XML Schema (I)
W3C standard,
http://www.w3.org/XML/Schema
‘extends’ DTD by providing significantly
enhanced possibilities to constrain the
content of attributes and elements
Object-oriented approach with types and
inheritance
But …
Detour: XML Schema (II)
"Over time, many people have complained
to the W3C about the complexity of DTDs
and have asked for something simpler.
W3C listened, assigned a committee to
work on the problem, and came up with a
solution that is much more complex than
DTDs ever were“
(Steven Holzner, "Inside XML", p.199)
The sample data
<gui:panel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.apachecon.com/talks/java-xml-binding"
xmlns:gui="http://www.apachecon.com/talks/java-xml-binding"
xmlns:xlink="http://www.w3.org/1999/xlink"
xsi:schemaLocation="http://www.apachecon.com/talks/java-xml-binding
file:gui.xsd">
<button
xlink:href="http://apachecon.com/2005/US/images/apachefeather_sm.gif"/>
<panel>
<panel/>
<label alignment="left">Some text</label>
<button text="Click me"/>
</panel>
<label alignment="center">Some other text</label>
</gui:panel>
The sample schema (I)
label-alignment-type
Restrict : xsd:token
Base Type xsd:token
button-type
text Type : xsd:string
Reference : xlink:href
Reference : xlink:type
Reference : xlink:show
Reference : xlink:actuate
label-type
Extend : xsd:string
Base Type xsd:string
alignment Type : gui:label-alignment-type
panel-type
button
Type gui:button-type
label
Type gui:label-type
panel
Type gui:panel-type
panel
Type gui:panel-type
The sample schema (II)
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xlink="http://www.w3.org/1999/xlink"
targetNamespace="http://www.apachecon.com/talks/java-xml-binding"
xmlns:gui="http://www.apachecon.com/talks/java-xml-binding"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xsd:import namespace="http://www.w3.org/1999/xlink"
schemaLocation="xlink.xsd"/>
<xsd:simpleType name="label-alignment-type">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="left"/>
<xsd:enumeration value="right"/>
<xsd:enumeration value="center"/>
</xsd:restriction>
</xsd:simpleType>
The sample schema (III)
<xsd:complexType name="button-type">
<xsd:attribute name="text"
<xsd:attribute ref="xlink:href"
<xsd:attribute ref="xlink:type"
<xsd:attribute ref="xlink:show"
<xsd:attribute ref="xlink:actuate"
</xsd:complexType>
type="xsd:string"/>
use="optional"/>
fixed="simple"/>
fixed="embed"/>
fixed="onLoad"/>
<xsd:complexType name="label-type">
<xsd:simpleContent>
<xsd:extension base="xsd:string">
<xsd:attribute name="alignment"
type="gui:label-alignment-type"
default="left"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
The sample schema (IV)
<xsd:complexType name="panel-type">
<xsd:sequence>
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element name="button" type="gui:button-type"/>
<xsd:element name="label" type="gui:label-type"/>
<xsd:element name="panel" type="gui:panel-type"/>
</xsd:choice>
<xsd:any namespace="##other"
processContents="lax"
minOccurs="0"
maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="panel" type="gui:panel-type"/>
</xsd:schema>
Schema Java compilers (I)
It generates Java classes (beans) from the
XML structure defined by a schema
Usually one Java class per (complex) type
Also performs datatype conversion
JSR-31, JAXB or "Java Architecture for XML
Binding", defines a standard
Presented tools: JAXB Reference
Implementation, JaxMe, XMLBeans
Other known tools: Castor
(http://www.castor.org), JBind
(http://jbind.sourceforge.net/jBind.html)
Schema Java compilers (II)
Benefits:
Generated code is usually fast
Code is strongly typed
Classes directly correspond to the Schema –
makes it easy to work with complex XML
Problems:
Requires an expressive Schema
Schema is the final authority
Generated code supports only one version of
the Schema
Is best suited when working with a fixed
Schema (version)
JAXB (I)
"Java Architecture for XML Binding"
JSR-31, JSR-222 (final review phase)
Special interest in the integration with web
service technology, esp. JAX-WS
Defines a standard binding scheme:
Specification for generating Java interfaces
and classes that correspond to XML Schema
elements
Standard API and infrastructure in the
java.xml.bind package
Basic customization options
JAXB 2: annotations describing the binding
JAXB (II)
JAXB (III)
Benefits (JAXB-specific)
Standard that will be (is) part of Java 6
Validation can be performed any time
Annotations may combine benefits of
Schema Java compilers & mapping
Problems (JAXB-specific)
XML Schema not fully supported
Generated classes are complicated
JAXB 2 is not fully backwards compatible
JAXB 1 & 2 RI
http://jaxb.dev.java.net/
Reference implementations for the JSRs as
required by the JCP
JAXB 1 is open source under the CDDL
JAXB 2 is currently Early Access and has a
quite limited license (evaluation only)
JAXB RI: Generated code (I)
public interface LabelType
{
java.lang.String getValue();
void setValue(java.lang.String value);
java.lang.String getAlignment();
void setAlignment(java.lang.String value);
}
public interface PanelType
{
java.util.List getAny();
java.util.List getButtonOrLabelOrPanel();
public interface Button extends javax.xml.bind.Element, test.jaxb.ButtonType
{}
public interface Label extends javax.xml.bind.Element, test.jaxb.LabelType
{}
public interface Panel extends javax.xml.bind.Element, test.jaxb.PanelType
{}
}
JAXB RI: Generated code (II)
public class ObjectFactory extends
test.jaxb.impl.runtime.DefaultJAXBContextImpl
{
public test.jaxb.Panel createPanel() throws
javax.xml.bind.JAXBException
{ return new test.jaxb.impl.PanelImpl(); }
public test.jaxb.PanelType createPanelType() throws
javax.xml.bind.JAXBException
{ return new test.jaxb.impl.PanelTypeImpl(); }
public test.jaxb.PanelType.Label createPanelTypeLabel() throws
javax.xml.bind.JAXBException
{ return new test.jaxb.impl.PanelTypeImpl.LabelImpl(); }
public test.jaxb.PanelType.Panel createPanelTypePanel() throws
javax.xml.bind.JAXBException
{ return new test.jaxb.impl.PanelTypeImpl.PanelImpl(); }
...
}
JAXB RI: Using it (I)
JAXBContext context = JAXBContext.newInstance("test.jaxb");
// read from a file
Unmarshaller unmarshaller = context.createUnmarshaller();
PanelType
panel
= (PanelType)unmarshaller.unmarshal(inputFile);
for (Iterator it = panel.getButtonOrLabelOrPanel().iterator(); it.hasNext();)
{
ModelBase modelObj = (ModelBase)it.next();
if (modelObj instanceof ButtonType)
{
System.out.println(((ButtonType)modelObj).getHref());
}
}
// write to a file
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty("jaxb.formatted.output", Boolean.TRUE);
marshaller.marshal(panel, new FileOutputStream(outputFile));
JAXB RI: Using it (II)
ObjectFactory
PanelType
ButtonType
PanelType
LabelType
factory
topLevelPanel
nestedButton
nestedPanel
nestedLabel
=
=
=
=
=
new ObjectFactory();
factory.createPanel();
factory.createPanelTypeButton();
factory.createPanelTypePanel();
factory.createPanelTypeLabel();
nestedButton.setHref("http://apachecon.com/2005/US/images/apachefeather_sm.gif");
nestedLabel.setAlignment("center");
nestedLabel.setValue("Some other text");
topLevelPanel.getButtonOrLabelOrPanel().add(nestedButton);
topLevelPanel.getButtonOrLabelOrPanel().add(nestedPanel);
topLevelPanel.getButtonOrLabelOrPanel().add(nestedLabel);
LabelType deepNestedLabel
ButtonType deepNestedButton
= factory.createPanelTypeLabel();
= factory.createPanelTypeButton();
deepNestedLabel.setValue("Some text");
deepNestedButton.setText("Click me");
nestedPanel.getButtonOrLabelOrPanel().add(factory.createPanelTypePanel());
nestedPanel.getButtonOrLabelOrPanel().add(deepNestedLabel);
nestedPanel.getButtonOrLabelOrPanel().add(deepNestedButton);
JAXB RI: Customizing
<jxb:bindings version="1.0"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
jxb:extensionBindingPrefixes="xjc">
<jxb:bindings schemaLocation="gui.xsd„
node="/xsd:schema">
<jxb:globalBindings>
<xjc:serializable uid="12343"/>
<xjc:superClass name="test.ModelBase"/>
</jxb:globalBindings>
<jxb:bindings node="//xsd:complexType[@name='panel-type']
/xsd:sequence/xsd:any">
<xjc:dom type="dom4j"/>
</jxb:bindings>
</jxb:bindings>
</jxb:bindings>
JAXB 2 RI: New stuff
Adds the new annotation-driven binding
facility which generates only annotated
classes
The object factory is no longer required
(though still available)
Lots of other improvements
Generates types for Schema simple types
Automatic mapping of xsd:any to DOM
Better complex type handling
JAXB 2 RI: Generated code (I)
@XmlAccessorType(AccessType.FIELD)
@XmlType(name = "label-type")
public class LabelType {
@XmlValue
protected String value;
@XmlAttribute protected LabelAlignmentType alignment;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public LabelAlignmentType getAlignment() {
return alignment;
}
public void setAlignment(LabelAlignmentType value) {
this.alignment = value;
}
}
JAXB 2 RI: Generated code (II)
@XmlEnum(String.class)
public enum LabelAlignmentType
{
@XmlEnumValue("center")
CENTER("center"),
@XmlEnumValue("left")
LEFT("left"),
@XmlEnumValue("right")
RIGHT("right");
public final String value;
LabelAlignmentType(String v)
{
value = v;
}
}
JaxMe 2
The first Apache project ;-)
JAXB1 implementation, currently version
0.5
http://ws.apache.org/jaxme
Only available open source implementation
(aside from the RI)
Not complete yet
No support
maxOccurs
No support
No support
for model groups with
>1
for xsd:any elements
for external binding files
JaxMe 2: Schema Changes
<xsd:complexType name="panel-type">
<xsd:sequence>
<xsd:element name="button"
type="gui:button-type"
minOccurs="0"/>
<xsd:element name="label"
type="gui:label-type"
minOccurs="0"/>
<xsd:element name="panel"
type="gui:panel-type"
minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
JaxMe 2: Generated code
public interface PanelType
{
public test.jaxme.ButtonType getButton();
public void setButton(test.jaxme.ButtonType pButton);
public test.jaxme.LabelType getLabel();
public void setLabel(test.jaxme.LabelType pLabel);
public test.jaxme.PanelType getPanel();
public void setPanel(test.jaxme.PanelType pPanel);
}
JaxMe 2: Differences to the RI (I)
Generated implementation classes are a lot
more readable
Integrates with databases (XML, relational)
Provides additional functionality
JaxMeAPI – Clean-room implementation of
the JAXB 1 API under Apache license
JaxMeJS – Source generation framework
JaxMeXS – Schema parser component
JaxMePM – Persistence management
functionality for reading/writing JAXB
objects from/to databases
JaxMe 2: Differences to the RI(II)
public class LabelTypeImpl implements test.jaxme.LabelType
{
private java.lang.String _alignment = "left";
private java.lang.String _value;
public java.lang.String getAlignment() {
return _alignment;
}
public void setAlignment(java.lang.String pAlignment) {
_alignment = pAlignment;
}
public java.lang.String getValue() {
return _value;
}
public void setValue(java.lang.String pValue) {
_value = pValue;
}
}
JaxMe 2: Outlook
Development is ongoing, but there are
currently only few developers
Upcoming features will make JaxMe really
useable
JAXME-61: maxOccurs > 1
JAXME-66: wildcards / xjc:dom
XMLBeans
http://xmlbeans.apache.org
Current released version is 2.0.0
Not compatible to JAXB, rather it can do
more
Provides 3 APIs to access the complete
infoset of the XML simultaneously
Generated Java classes
XML Cursor API for navigation
XPath & XQuery support
Provides access to the Schema type system
itself
XMLBeans: Generated code (I)
XMLBeans: Generated code (II)
public interface ButtonType extends org.apache.xmlbeans.XmlObject {
java.lang.String
getText();
org.apache.xmlbeans.XmlString xgetText();
boolean
isSetText();
void
setText(java.lang.String text);
void
xsetText(org.apache.xmlbeans.XmlString text);
void
unsetText();
// same for href, type, show, actuate ...
public static final class Factory {
public static test.xmlbeans.ButtonType newInstance() {
...
}
public static test.xmlbeans.ButtonType parse(java.lang.String xmlAsString)
throws org.apache.xmlbeans.XmlException {
...
}
public static test.xmlbeans.ButtonType parse(java.io.File file)
throws org.apache.xmlbeans.XmlException, java.io.IOException {
...
}
...
}
}
XMLBeans: Generated code (III)
public interface PanelType extends org.apache.xmlbeans.XmlObject
{
java.util.List<test.xmlbeans.ButtonType> getButtonList();
test.xmlbeans.ButtonType[]
getButtonArray();
test.xmlbeans.ButtonType
getButtonArray(int i);
int
sizeOfButtonArray();
void setButtonArray(test.xmlbeans.ButtonType[] buttonArray);
void setButtonArray(int i, test.xmlbeans.ButtonType button);
test.xmlbeans.ButtonType insertNewButton(int i);
test.xmlbeans.ButtonType addNewButton();
void
removeButton(int i);
// same for Label and Panel
public static final class Factory
{
...
}
}
XMLBeans: Using it
// read from Xml
PanelType panel = PanelType.Factory.parse(inputFile);
// create the
PanelDocument
PanelType
ButtonType
PanelType
LabelType
panel manually and write it to Xml
panelDoc
= PanelDocument.Factory.newInstance();
topLevelPanel = panelDoc.addNewPanel();
nestedButton = topLevelPanel.addNewButton();
nestedPanel
= topLevelPanel.addNewPanel();
nestedLabel
= topLevelPanel.addNewLabel();
nestedButton.setHref("http://apachecon.com/2005/US/images/apachefeather_sm.gif");
nestedLabel.setAlignment(LabelAlignmentType.CENTER);
nestedLabel.setStringValue("Some other text");
PanelType deepNestedPanel
LabelType deepNestedLabel
ButtonType deepNestedButton
= nestedPanel.addNewPanel();
= nestedPanel.addNewLabel();
= nestedPanel.addNewButton();
deepNestedLabel.setStringValue("Some text");
deepNestedButton.setText("Click me");
panelDoc.save(outputFile, new XmlOptions().setSavePrettyPrint());
XMLBeans: Additional APIs
// read from Xml
PanelType panel = PanelType.Factory.parse(inputFile);
XmlCursor cursor = panel.newCursor();
// now the cursor is at the start of the document
cursor.toFirstChild();
// now at the start of the panel
cursor.toEndToken();
// now just before the end of the panel
cursor.insertElementWithText("documentation",
"http://www.someotherlocation.net/example",
"XMLBeans was here");
cursor.dispose();
// write to Xml
panel.save(outputFile, new XmlOptions().setSavePrettyPrint());
XMLBeans: Benefits
Full support of the XML Schema standard
Fine grained access to the complete infoset
of the XML document (including XML
comments)
Great documentation
Unmarshalling is on-demand (incremental)
Validation against the Schema is built into
the generated classes
XMLBeans: Problems
Generated code is complicated
There is no easy way to extend the
generated types
The sample model
XMLSerialization
Valid option if XML structure is not
important
Conceptually equal to normal serialization
but also portable
XML structure is driven by Java model
Uses reflection to extract information at
runtime
Extremely simple to use
No Apache project
Others: JSX (http://jsx.org) & XStream
XStream
http://xstream.codehaus.org
BSD license, current version is 1.1.2
Fully features serialization library
Some core features
Support for non-public fields (including
private and final)
Support for non-public and inner classes
Classes are also not required to have default
or no-argument constructor
Support for Java 5 enumerations
XStream: Usage
XStream xstream = new XStream();
Panel
panel
= getTestModel();
// write to file
xstream.toXML(panel, new FileWriter(outputFile));
// read from file
panel = (Panel)xstream.fromXML(new FileReader(inputFile));
XStream: Output
<test.model.Panel>
<__children>
<test.model.Button>
<__imageUrl>http://apachecon.com/2005/US/images/apachefeather_sm.gif</__imageUrl>
</test.model.Button>
<test.model.Panel>
<__children>
<test.model.Panel>
<__children/>
</test.model.Panel>
<test.model.Label>
<__text>Some text</__text>
<__alignment>
<iValue>1</iValue>
<iName>left</iName>
</__alignment>
</test.model.Label>
<test.model.Button>
<__text>Click me</__text>
</test.model.Button>
</__children>
</test.model.Panel>
<test.model.Label>
<__text>Some other text</__text>
<__alignment>
<iValue>1</iValue>
<iName>center</iName>
</__alignment>
</test.model.Label>
</__children>
</test.model.Panel>
XStream: Customization
xstream.registerConverter(new Converter() {
public boolean canConvert(Class type) {
return AlignmentEnum.class.equals(type);
}
public void marshal(Object source, HierarchicalStreamWriter writer,
MarshallingContext context) {
writer.setValue(((AlignmentEnum)source).getName());
}
public Object unmarshal(HierarchicalStreamReader reader,
UnmarshallingContext context) {
return AlignmentEnum.getEnum(reader.getValue());
}
});
xstream.alias("panel", Panel.class);
xstream.alias("label", Label.class);
xstream.alias("button", Button.class);
xstream.aliasField("text", Label.class, "_text");
xstream.aliasField("alignment", Label.class, "_alignment");
xstream.aliasField("text", Button.class, "_text");
xstream.aliasField("href", Button.class, "_imageUrl");
xstream.addImplicitCollection(Panel.class, "_children");
XStream: Customized output
<panel>
<button>
<href>http://apachecon.com/2005/US/images/apachefeather_sm.gif</href>
</button>
<panel>
<panel/>
<label>
<text>Some text</text>
<alignment>left</alignment>
</label>
<button>
<text>Click me</text>
</button>
</panel>
<label>
<text>Some other text</text>
<alignment>center</alignment>
</label>
</panel>
Java <-> XML mapping
Maps between (existing) Java classes and
(pre-defined) XML structure
Most flexible approach
Mapping interpretation can be
Generated and added to the Application
Static mapping
Interpreted at runtime (via reflection)
Dynamic mapping
Apache projects: commons-betwixt
Others: JiBX, Javolution
(http://javolution.org/)
JiBX
http://jibx.sourceforge.net
license is BSD, current version is 1.0 RC1
Static mapping with bytecode enhancement
External XML file defines mapping
Also contains a Schema JiBX tool in
alpha stage
Creates Java classes & JiBX mapping from
the Schema
Both can then be adjusted as needed
JiBX: Mapping definition
<binding>
<mapping name="panel“ class="test.model.Panel">
<collection field="_children“ item-type="test.model.ModelObject"
type="java.util.ArrayList"/>
</mapping>
<mapping name="label“ class="test.model.Label">
<value style="text“ field="_text“ usage="optional"/>
<value style="attribute“ name="alignment“ usage="required"
get-method="getAlignment“ set-method="setAlignment"
serializer="test.AlignmentEnumConverter.alignmentEnumToString"
deserializer="test.AlignmentEnumConverter.alignmentEnumFromString"/>
</mapping>
<mapping name="button“ class="test.model.Button">
<namespace uri="http://www.w3.org/1999/xlink“ prefix="xlink"/>
<value style="attribute“ name="text“ usage="optional"
get-method="getText“ set-method="setText"/>
<value style="attribute“ name="href“
field="_imageUrl“ usage="optional“
ns="http://www.w3.org/1999/xlink“/>
</mapping>
</binding>
JiBX: Customizing
package test;
import test.model.AlignmentEnum;
public class AlignmentEnumConverter
{
public static String alignmentEnumToString(AlignmentEnum value)
{
return value.getName();
}
public static AlignmentEnum alignmentEnumFromString(String value)
{
return AlignmentEnum.getEnum(value);
}
}
JiBX: Usage
IBindingFactory factory = BindingDirectory.getFactory(Panel.class);
// write to XML
IMarshallingContext marshaller = factory.createMarshallingContext();
marshaller.setIndent(4);
marshaller.marshalDocument(getTestModel(),
"ISO-8859-1",
null,
new FileWriter(outputFile));
// read from XML
IUnmarshallingContext unmarshaller = factory.createUnmarshallingContext();
Panel panel = (Panel)unmarshaller.unmarshalDocument(new FileReader(inputFile),
null);
JiBX: Output
<?xml version="1.0" encoding="ISO-8859-1"?>
<panel>
<button xmlns:xlink="http://www.w3.org/1999/xlink“
xlink:href="http://apachecon.com/2005/US/images/apachefeather_sm.gif"/>
<panel>
<panel></panel>
<label alignment="left">Some text</label>
<button xmlns:xlink="http://www.w3.org/1999/xlink" text="Click me"/>
</panel>
<label alignment="center">Some other text</label>
</panel>
JiBX: Benefits & Problems
Benefits
It is fast because the mapping is compiled
into code
Mapping is powerful and easily customizable
Problems
Learning it takes time
Maps only what is specified in the mapping
Some quirks in the Ant task and
commandline tool
Betwixt
http://jakarta.apache.org/commons/betwixt
Current version is 0.7
Dynamic mapping tool
Can be used like XML serializers without a
mapping definition
Mapping overrides in external files
One per Class (.betwixt)
In one file
Uses commons-digester which allows for
extended customization abilities
Betwixt: Basic usage (II)
Panel panel = getTestModel();
// write to XML
FileWriter output = new FileWriter(outputFile);
BeanWriter writer = new BeanWriter(output);
writer.enablePrettyPrint();
output.write("<?xml version='1.0' ?>\n");
writer.write(panel);
output.close();
// read from XML
BeanReader reader = new BeanReader();
reader.registerBeanClass(Panel.class);
reader.registerBeanClass(Label.class);
reader.registerBeanClass(Button.class);
panel = (Panel)reader.parse(new FileReader(inputFile));
Betwixt: Basic usage (II)
<Panel id="1">
<children>
<child id="2">
<imageUrl id="3">
<authority>apachecon.com</authority>
<content/>
<defaultPort>80</defaultPort>
<file>
/2005/US/images/apachefeather_sm.gif
</file>
<host>apachecon.com</host>
<path>
/2005/US/images/apachefeather_sm.gif
</path>
<port>-1</port>
<protocol>http</protocol>
<query/>
<ref/>
<userInfo/>
</imageUrl>
<text/>
</child>
<child id="4">
<children>
<child id="5">
<children/>
</child>
<child id="6">
<alignment id="7">
<enumClass>
test.model.AlignmentEnum
</enumClass>
<name>left</name>
<value>1</value>
</alignment>
<text>Some text</text>
</child>
<child id="8">
<text>Click me</text>
</child>
</children>
</child>
<child id="9">
<alignment id="10">
<enumClass>
test.model.AlignmentEnum
</enumClass>
<name>center</name>
<value>1</value>
</alignment>
<text>Some other text</text>
</child>
</children>
</Panel>
Betwixt: Customization (I)
FileWriter output = new FileWriter(outputFile);
BeanWriter writer = new BeanWriter(output);
writer.getBindingConfiguration().setObjectStringConverter(
new AlignmentEnumStringConverter());
writer.getXMLIntrospector().getConfiguration().getPrefixMapper().setPrefix(
"http://www.w3.org/1999/xlink", "xlink");
writer.getXMLIntrospector().register(new InputSource("mapping.xml"));
writer.enablePrettyPrint();
output.write("<?xml version='1.0' ?>\n");
writer.write(panel);
output.close();
BeanCreationList chain = BeanCreationList.createStandardChain();
BeanReader
reader = new BeanReader();
chain.insertBeanCreator(1, new ButtonCreator());
reader.getReadConfiguration().setBeanCreationChain(chain);
reader.getXMLIntrospector().getConfiguration().getPrefixMapper().setPrefix(
"http://www.w3.org/1999/xlink", "xlink");
reader.registerMultiMapping(new InputSource("mapping.xml"));
reader.getBindingConfiguration().setObjectStringConverter(
new AlignmentEnumStringConverter());
panel = (Panel)reader.parse(new FileReader(inputFile));
Betwixt: Customization (II)
public class ButtonCreator implements ChainedBeanCreator
{
public Object create(ElementMapping mapping, ReadContext context,
BeanCreationChain chain) {
return "button".equals(mapping.getName()) ?
new Button(mapping.getAttributes().getValue("text")) :
chain.create(mapping, context);
}
}
public class AlignmentEnumStringConverter extends ConvertUtilsObjectStringConverter
{
public String objectToString(Object object, Class type, Context context)
{
return AlignmentEnum.class.equals(type) ?
((AlignmentEnum)object).getName() :
super.objectToString(object, type, context);
}
public Object stringToObject(String value, Class type, Context context) {
return AlignmentEnum.class.equals(type) ?
AlignmentEnum.getEnum(value) :
super.stringToObject(value, type, context);
}
}
Betwixt: Mapping file
<betwixt-config>
<class name=“test.model.Panel”>
<element name=“panel”>
<element property=“children” updater=“addChild”/>
<addDefaults add-adders=“false”/>
</element>
</class>
<class name=“test.model.Label”>
<element name=“label”>
<attribute name=“alignment” property=“alignment”/>
<text property=“text”/>
</element>
</class>
<class name=“test.model.Button”>
<element name=“button”>
<attribute name=“text” property=“text”/>
<attribute name=“href” property=“imageUrl”
uri=“http://www.w3.org/1999/xlink”/>
</element>
</class>
</betwixt-config>
Betwixt: Output
<?xml version='1.0' ?>
<panel id="1">
<button xlink:href=
"http://apachecon.com/2005/US/images/apachefeather_sm.gif"
id="2"
xmlns:xlink="http://www.w3.org/1999/xlink"/>
<panel id="3">
<panel id="4"/>
<label alignment="left" id="5">Some text</label>
<button text="Click me" id="6"/>
</panel>
<label alignment="center" id="7">Some other text</label>
</panel>
Betwixt: Annotations (I)
@XmlElement(localName = "panel")
public class Panel implements ModelObject
{
private List _children = new ArrayList();
@XmlCollection(updater = "addChild")
public List getChildren()
{
return _children;
}
public void setChildren(List children)
{
_children = children;
}
public void addChild(ModelObject obj)
{
_children.add(obj);
}
}
Betwixt: Annotations (II)
@XmlElement(localName = "label")
public class Label extends VisualModelObject {
private String _text;
private AlignmentEnum _alignment;
...
public String getText() {
return _text;
}
@XmlText()
public void setText(String text) {
_text = text;
}
public AlignmentEnum getAlignment() {
return _alignment;
}
@XmlAttribute(localName = "alignment")
public void setAlignment(AlignmentEnum alignment) {
_alignment = alignment;
}
}
Betwixt: Annotations (III)
Panel
FileWriter
BeanWriter
XMLIntrospector
panel
writer
beanWriter
introspector
=
=
=
=
getTestModel();
new FileWriter(outputFile);
new BeanWriter(writer);
new AnnotationIntrospector();
introspector.getConfiguration().getPrefixMapper().setPrefix(
"http://www.w3.org/1999/xlink", "xlink");
beanWriter.setXMLIntrospector(introspector);
beanWriter.getBindingConfiguration().setObjectStringConverter(
new AlignmentEnumStringConverter());
beanWriter.enablePrettyPrint();
beanWriter.setWriteEmptyElements(true);
writer.write("<?xml version='1.0' ?>\n");
beanWriter.write(panel);
writer.close();
Betwixt: Benefits & Problems
Benefits
Works reasonably out-of-the-box
Mapping definition is relatively simple
Powerful customizations
Annotations make mapping simpler
Can map to DynaBeans
Problems
Bean-centric
Reading/writing seems more complicated
Slow
Docs need enhancement
Performance
Performance is important but not a focus of
this talk - still …
Performance of the approaches differs a lot
Comparing them is not really fair
General observations
Generated (byte)code usually leads to good
performance
Binding at tuntime (dynamic mapping) is a
slower but usually more flexible
Might be a choice between speed and
flexibility
Choosing the ‘right’ approach
Depends on what is fixed, XML and/or Java
If XML is fixed
If XML structure is complex
Schema Java compiler
Else
Java – XML Mapping
If Java is fixed
If XML structure is not important
XML Serialization
Else
Java – XML Mapping