You are on page 1of 48

The Java

Architecture For
)XML Binding )JAXB
:By
Yoav Zibin
Sharon Krisher
Motivation for JAXB
 The main purpose of XML Schema is:
 Validation of XML documents
 Any other purposes?
 Hint 1: determinism requirement
 Hint 2: the “default” attribute has nothing to do
with validation
<xs:attribute name="country" use=“optional”
default="Israel“ />
 Answer: Given a valid XML document, its
schema defines a unique data model
Motivation for JAXB
 Problem: How to manipulate this data model?
 DOM )data object model) solution:
 Pros: simple, general )a schema is not even required)
 Cons: no types, no compile-time checking
DOM pseudo-code example
root.getChild("Address").getChild("Number").getText()

 I wish to write … returns a string

root.getAddress().getNumber()

returns a number
JAXB solution:
Mapping XML Schema to Java interfaces

Binding Compiler

Source Java
schema interface
s

Pros: preserve types, compile-time checking


Cons: complex, specific to a certain schema
<xs:complexType name="AddressType">
<xs:sequence>
<xs:element name="Number" type="xs:unsignedInt"/>
<xs:element name="Street" type="xs:string"/>
</xs:sequence>
</xs:complexType>

Binding Compiler

public interface AddressType {


long getNumber();
void setNumber(long value);
Must be non-negative
String getStreet();
void setStreet(String value);
} Must be non-null
Talk Outline
 How is XML Schema mapped to Java
interfaces?
 What is the default mapping?
 How to customize this mapping?

 Second part of the lecture

 How do I use those Java interfaces?


 Next slides and a Demo!
Main Features
 Unmarshal: xml  objects
 Create / Read / Update / Delete objects
 Validate objects
 Marshal: objects  xml
 No roundtrip guarantees
 Marshal) Unmarshal)xml) ) ≠ xml
 We found that order is not always preserved

 But usually roundtrip holds


Step 1: Create XML Schema
Demo.xsd
<xs:element name="Person" type="PersonType"/>
<xs:complexType name="PersonType">
<xs:sequence>
<xs:element name=“Name" type="xs:string"/>
<xs:element name="Address" type="AddressType"
minOccurs="1" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="AddressType">
<xs:sequence>
<xs:element name="Number" type="xs:unsignedInt"/>
<xs:element name="Street" type="xs:string"/>
</xs:sequence>
</xs:complexType>
Step 2: Create XML Document
Demo.xml
<Person
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="C:\JAXB Demo\demo.xsd">
<Name>Sharon Krisher</Name>
<Address>
<Street>Iben Gevirol</Street>
<Number>57</Number>
</Address>
<Address>
<Street>Moshe Sharet</Street>
<Number>89</Number>
</Address>
</Person>

Check that your XML conforms to the Schema


Step 3: Run the binding compiler
 %JWSDP_HOME%\jaxb\bin\xjc -p demo demo.xsd
 A package named demo is created
)in the directory demo)
 The package contains )among other things):

 interface AddressType
 interface PersonType
AddressType and PersonType
public interface AddressType {
Must be non-negative
long getNumber();
void setNumber(long value);

String getStreet();
void setStreet(String value);
}
Must be non-null

public interface PersonType { Must be non-null


String getName();
void setName(String value);

/* List of AddressType */ Must contain at least one item


java.util.List getAddress();
}
In Java1.5: List<AddressType>
Step 4: Create Context
 The context is the entry point to the API
 Contains methods to create Marshaller,
Unmarshaller and Validator instances

JAXBContext context = JAXBContext.newInstance("demo");

The package name is demo


)Recall: xjc -p demo demo.xsd)
Step 5: Unmarshal: xml -> objects

Unmarshaller unmarshaller = Enable validation of


context.createUnmarshaller(); xml according to the
schema while
unmarshaller.setValidating(true); unmarshalling
PersonType person =
(PersonType) unmarshaller.unmarshal(
new FileInputStream("demo.xml") );
Step 6: Read

System.out.println("Person name=" +
person.getName() );

AddressType address = (AddressType)


person.getAddress().get(0);

System.out.println("First Address: " +


" Street=" + address.getStreet() +
" Number=" + address.getNumber() );
Step 7: Manipulate objects
// Update
person.setName("Yoav Zibin");

// Delete
List addressList = person.getAddress();
addressList.clear();
What happens if we validate there?
// Create
ObjectFactory objectFactory = new ObjectFactory();
AddressType newAddr = objectFactory.createAddressType();
newAddr.setStreet("Hanoter");
part of the demo package
newAddr.setNumber(5);
addressList.add( newAddr );
uses the factory pattern
Step 8: Validate on-demand
Validator validator = context.createValidator();

validator.validate(newAddr);

Check that we have set Street and Number,


and that Number is non-negative

validator.validate(person);

Check that we have set Name, and that


Address contains at least one item
Step 9: Marshal: objects -> xml
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
Boolean.TRUE);
marshaller.marshal(person,
new FileOutputStream("output.xml"));

output.xml
<Person>
<Name>Yoav Zibin</Name>
<Address>
<Street>Hanoter</Street>
<Number>5</Number>
</Address>
</Person>
!And now, the Demo
First Part Summary
Similar Technologies
 Liquid XML Data Binding
 Similar to JAXB
 Supports all Schema constructs

 In addition to Java: C#, C++, Visual Basic 6

 Relaxer
 Instead of Schema uses Relax
 Castor.org
Second Part Outline
 Validation
 Mapping XML Schema to Java
 Naming
 Java Properties

 Simple and Complex Types

 Customization of the default mapping


Validation Constraints
 Three categories of constraints
 Type constraints: Legal values in simple types
 E.g., in every address, number is a non-negative
integer
 Local structural constraints
 E.g., in every person, address contains at least
one item
 Global structural constraints
 E.g., ID and IDREF
Validation
 Three forms of validation
 Unmarshal time validation )at unmarshal time)
 On-demand validation )at any chosen point in time)
 validateRoot)object) vs. validate)object)
 validateRoot includes global constraint checking
 Fail-fast validation )at all times)
 Currently not implemented
 Checks that the value provided to a set method is legal
 When validation errors occur an event is raised
)no exception) and validation continues, so that
several validation errors can be handled.
 Default handler raises an exception on first error
Unsupported Schema Concepts
 Substitution groups
 Type substitutions )xsi:type, block)
 Key, keyref, and unique
 anyAttribute

 No support for XPath or any other query


langauge 
Element vs. Type
 An element also has a qualified name
<xs:element name=“ugly_man" type="PersonType"/>
<xs:element name=“pretty_woman" type="PersonType"/>
<xs:complexType name="PersonType"> … </xs:complexType>

an empty interface which marks


the existence of a static QName

interface UglyMan extends PersonType, Element {}


interface PrettyWoman extends PersonType, Element {}
interface PersonType { … }

 When is the difference important? )next)


?When must I use elements
 Marshal: marshaller.marshal(Object, OutputStream)

E.g., when we marshal a PersonType:


<Name>Sharon Krisher</Name>
must be an element,
<Address>
<Street>Iben Gevirol</Street>
otherwise the resulting
<Number>57</Number> output is not a legal XML
</Address>

 General content
<xs:any/> Object getAny();
void setAny(Object elementOrValue);
Naming
 Problem: sometimes XML names
 are not legal java names
 do not comply to java naming standards

 The binding compiler creates proper


names
XML Name Class Name Method Name
mixedCaseName MixedCaseName getMixedCaseName
name-with-dash NameWithDash getNameWithDash
aa_bb-cc AaBbCc getAaBbCc
Java Properties
 Local schema components are mapped to:
 Simple property )get, set)
String getName();
void setName(String value);

 With customization: isSetName , unsetName


 List property
In Java1.5:
java.util.List getAddress(); List<AddressType>

 Indexed property )next)


Indexed Property
 Used instead of a list property when a
proper customization is applied

AddressType[] getAddress();
void setAddress(AddressType[] value);

AddressType getAddress(int index);


void setAddress(int index, AddressType value);
General Content Property
 The most general content property
 Can represent any content, however complex
 A list that can contain element interfaces and values
 Used for “problematic cases” :
 Name collisions due to derivation
 Mixed content
 Another example:
<xs:any maxOccurs="unbounded"/>
Each item can be
some element or
List getAny();
value
)Simple Types )partial diagram
SimpleType

Primtive List Union Restriction

List Next (1)


Represented as
validation
ID/IDREF String/Object constraints

date Calendar
maxInclusive

integer BigInteger
Enumeration
int int Next (2)
Simple Type:Union
<xs:complexType name="Date">
<xs:sequence>
<xs:element name="Month">
<xs:simpleType>
<xs:union memberTypes="xs:int xs:string"/>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:complexType>

Common supertype
Public interface Date { of )Integer, String)
Object getMonth(); is Object
void setMonth(Object);
}
Type SafeEnumeration
<xs:simpleType name="USState">
<xs:restriction base="xs:NCName">
<xs:enumeration value="AK"/>
<xs:enumeration value="NY"/>
</xs:restriction>
</xs:simpleType>

public class USState {


protected USSate(String v) {…}
public static final USState AK = …;
public static final USState NY = …;
public String getValue();
public static USState fromValue(String v) {…}
}
XML Schema Type System
Any

SimpleType finished ComplexType Represented as


a Java interface

SimpleContent ComplexContent *Sequence * Choice * All

*Extension Extension
Elements
Attributes
Restriction
abstract
*
The interface
use
default
nillable
minOccurs *
fixed maxOccurs
extends the base
type’s interface Represented as
( ) Next
* Java properties
Complex Types
 Represented as a Java interface
 Anonymous type
 An interface is created.
 The name is derived from the name of the

schema element + “Type”, e.g Foo  FooType


 Abstract types: no create method in
ObjectFactory
Complex Type: Simple Content
<xs:complexType name=“InternationalPrice">
<xs:simpleContent>
<xs:extension base="xs:int">
<xs:attribute name="currency“ type="xs:string"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>

interface InternationalPrice {
int getValue();
void setValue(int);

String getCurrency();
void setCurrency(String);
}
Complex Type:Aggregation
<xs:element name="A" type="xs:int"/>

<xs:complexType name="Foo"> <xs:complexType name="Foo">


<xs:sequence> <xs:sequence>
<xs:element ref="A"/> <xs:element ref="A"/>
<xs:sequence>
<xs:element ref="B"/> <xs:element ref="B"/>
<xs:element ref="C"/> <xs:element ref="C"/>
</xs:sequence>
</xs:sequence> </xs:sequence>
</xs:complexType> </xs:complexType>

interface Foo {
int getA(); void setA(int);
int getB(); void setB(int);
int getC(); void setC(int);
}
Complex Type: Mixed Content
<xs:complexType name=“LetterBody"
mixed="true">
<xs:sequence>
<xs:element name="name" type="xs:string"/>

</xs:sequence> XML fragment
</xs:complexType> Dear Mr.<name>Robert Smith</name>, …

interface lb
LetterBody LetterBody {
= ObjectFactory.createLetterBody();
interface
List gcl Name extends Element {
= lb.getContent();
String
gcl.add("Dear getValue();
Mr.");
void setValue(String);
gcl.add(ObjectFactory.createLetterBodyName("Robert Smith"));
}
… The list may contain
List getContent(); elements and strings
}
Complex Type:Choice
<xs:complexType name="FooBarType">
The programmer
<xs:choice>
is responsible to
<xs:element name="Foo" type="xs:int"/>
only set one of
<xs:element name="Bar"
Foo or Bar
type="xs:string"/>
</xs:choice>
Default
</xs:complexType>
Customization (Not implemented yet) public interface FooBarType {
int getFoo();
public interface FooBarType {
void setFoo(int value);
Object getFooOrBar();
String getBar();
void setFooOrBar(Object);
void setBar(String value);
}
boolean isSetFoo();
Common supertype of void unsetFoo();
)Integer, String) is boolean isSetBar();
Object void unsetBar();
Similar to union }
WhenmaxOccurs>1
<xs:complexType name="FooBarType">
<xs:choice maxOccurs="unbounded">
<xs:element name="Foo" type="xs:int"/>
<xs:element name="Bar" type="xs:string"/>
</xs:choice>
</xs:complexType>

public interface FooBarType {


interface Foo extends Element {…}
interface Bar extends Element {…}
// Items are instances of Foo and Bar
List getFooOrBar();
}

For a sequence: List getFooAndBar()


The programmer needs to make sure that
the list contains sequences of <A,B>.
Complex Type:All
 Mapped like Sequence
 Can’t have maxOccurs > 1
 No way to specify the order of elements
 Round trip doesn’t hold )order is not preserved):
unmarshal
XML
Objects
≠ in
memory
XML
marshal
Nillable elements
<xs:element name=“age" type=“xs:int" nillable="true"/>

Integer getAge();
void setAge(Integer value);

Java: setAge( new Integer(25) ) or setAge(null)

XML: <age>25</age> or <age xsi:nil="true"/>


Customization
 Used to augment the default mapping
 Customizations declared via special xml
tags
 May appear inside the source schema or
in a separate file
Uses of Customization
 Change default names of interfaces and
properties
 For a specific schema construct
 For an entire namespace

 Add a suffix or a prefix


 Change the types of properties
 Add javadoc declarations
Software Engineering Issues
 Weak Typing
Our suggestions:
 Marshal / Unmarshal : Object  Element
 IDREF: Object  Identifiable

 Sometimes JAXB doesn’t allow us to


control the order of elements
 Example 1: xs:all
 Example 2: next slide
Element Order Example
<xs:complexType name=“ABType">
<xs:choice>
<xs:sequence>
<xs:element name="A" type="xs:int"/>
<xs:element name="B" type="xs:string"/>
</xs:sequence>
<xs:sequence>
<xs:element name="B" type="xs:string"/>
<xs:element name="A" type="xs:int"/>
</xs:sequence> obj.setA(5);
</xs:choice> obj.setB(“a”);
</xs:complexType>
What happens
when we marshal
public interface ABType { obj?
int getA(); void setA(int value);
String getB(); void setB(String value); No roundtrip
}
It’s the programmer’s fault
 Taken from JAXB specification:
 “The caller must be sure …”
 “There is an expectation …”

 “User is responsible …”

 “… unexpected behavior may occur.”

Question: What is the output ?


xs:choice between Foo and Bar
obj.setAge(42);
obj.setFoo(42);
42 true
obj.unsetAge();
obj.setBar("A");
System.out.println(
System.out.println( obj.getAge() );
obj.isSetFoo() );
The END

 Any questions?

You might also like