Sunteți pe pagina 1din 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
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
types 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


Cant have maxOccurs > 1
No way to specify the order of elements
Round trip doesnt 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 doesnt 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

Its the programmers 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?

S-ar putea să vă placă și