Download Java-XML-Mapping

Document related concepts
no text concepts found
Transcript
Java-XML binding approaches
@ Apache
© 2005 Thomas Dudziak
[email protected]
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
Related documents