The Java Architecture For XML Binding (JAXB)

Download Report

Transcript The Java Architecture For XML Binding (JAXB)

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
schema
Java
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);
String getStreet();
void setStreet(String value);
}
Must be non-negative
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 {
long getNumber();
void setNumber(long value);
Must be non-negative
String getStreet();
void setStreet(String value);
}
Must be non-null
public interface PersonType {
String getName();
void setName(String value);
/* List of AddressType */
java.util.List getAddress();
}
In Java1.5: List<AddressType>
Must be non-null
Must contain at least one item
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 =
context.createUnmarshaller();
unmarshaller.setValidating(true);
Enable validation of xml
according to the
schema while
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");
newAddr.setNumber(5);
addressList.add( newAddr );
part of the demo package
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


Local structural constraints


E.g., in every address, number is a non-negative
integer
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)



Fail-fast validation (at all times)




validateRoot(object) vs. validate(object)
validateRoot includes global constraint checking
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>
<Address>
<Street>Iben Gevirol</Street>
<Number>57</Number>
</Address>

must be an element,
otherwise the resulting
output is not a legal XML
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
java.util.List getAddress();

Indexed property (next)
In Java1.5:
List<AddressType>
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
value
List getAny();
Simple Types (partial diagram)
SimpleType
Primtive
ID/IDREF
date
integer
List
Union
List
Next (1)
String/Object
Calendar
Restriction
Represented as
validation
constraints
maxInclusive
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>
Public interface Date {
Object getMonth();
void setMonth(Object);
}
Common supertype of
(Integer, String) is
Object
Type Safe Enumeration
<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
SimpleContent ComplexContent
*Extension
*Sequence * Choice
Extension
The interface
extends the base
type’s interface
*
*
All
Elements
Attributes
Restriction
( ) Next
Represented as
a Java interface
use
default
fixed
abstract
nillable
minOccurs
maxOccurs
Represented as
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:sequence>
<xs:element ref="A"/>
<xs:sequence>
<xs:element ref="B"/>
<xs:element ref="C"/>
</xs:sequence>
</xs:sequence>
</xs:complexType>
<xs:complexType name="Foo">
<xs:sequence>
<xs:element ref="A"/>
<xs:element ref="B"/>
<xs:element ref="C"/>
</xs:sequence>
</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
Name extends Element {
List gcl
= lb.getContent();
String
getValue();
gcl.add("Dear
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">
<xs:choice>
<xs:element name="Foo" type="xs:int"/>
<xs:element name="Bar" type="xs:string"/>
</xs:choice>
</xs:complexType>
Default
Customization (Not implemented yet)
public interface FooBarType {
Object getFooOrBar();
void setFooOrBar(Object);
}
Common supertype of
(Integer, String) is
Object
Similar to union
The programmer
is responsible to
only set one of
Foo or Bar
public interface FooBarType {
int getFoo();
void setFoo(int value);
String getBar();
void setBar(String value);
boolean isSetFoo();
void unsetFoo();
boolean isSetBar();
void unsetBar();
}
When maxOccurs>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
≠
XML
Objects
in
memory
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>
</xs:choice>
</xs:complexType>
public interface ABType {
int getA();
void setA(int value);
String getB(); void setB(String value);
}
obj.setA(5);
obj.setB(“a”);
What happens
when we marshal
obj?
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);
42true
obj.setFoo(42);
obj.unsetAge();
obj.setBar("A");
System.out.println(
obj.getAge() );
);
System.out.println(
obj.isSetFoo()
The END

Any questions?