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
I wish to write …
root.getChild("Address").getChild("Number").getText()
DOM pseudo-code example
root.getAddress().getNumber()
returns a number
returns a string
Binding Compiler
Java interfaces
Java interfaces
Source schema
Source schema
JAXB solution: Mapping XML Schema to Java interfaces
Pros: preserve types, compile-time checkingCons: complex, specific to a certain schema
Binding Compiler
<xs:complexType name="AddressType"> <xs:sequence> <xs:element name="Number" type="xs:unsignedInt"/> <xs:element name="Street" type="xs:string"/> </xs:sequence></xs:complexType>
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
<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>
Demo.xsd
Step 2: Create XML Document
<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
Demo.xml
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 PersonTypepublic interface AddressType { long getNumber(); void setNumber(long value);
String getStreet(); void setStreet(String value);}
public interface PersonType { String getName(); void setName(String value);
/* List of AddressType */ java.util.List getAddress(); }
In Java1.5: List<AddressType>
Must contain at least one item
Must be non-negative
Must be non-null
Must be non-null
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);
PersonType person = (PersonType) unmarshaller.unmarshal(
new FileInputStream("demo.xml") );
Enable validation of xml according to the
schema while unmarshalling
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();
part of the demo package
uses the factory pattern
// Create
ObjectFactory objectFactory = new ObjectFactory();
AddressType newAddr = objectFactory.createAddressType();
newAddr.setStreet("Hanoter");
newAddr.setNumber(5);
addressList.add( newAddr );
What happens if we validate there?
Step 8: Validate on-demand
Validator validator = context.createValidator();
validator.validate(newAddr);
validator.validate(person);
Check that we have set Street and Number, and that Number is non-negative
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"));
<Person> <Name>Yoav Zibin</Name> <Address> <Street>Hanoter</Street> <Number>5</Number> </Address></Person>
output.xml
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
When is the difference important? (next)
<xs:element name=“ugly_man" type="PersonType"/> <xs:element name=“pretty_woman" type="PersonType"/><xs:complexType name="PersonType"> … </xs:complexType>
interface UglyMan extends PersonType, Element {} interface PrettyWoman extends PersonType, Element {}interface PersonType { … }
an empty interface which marks the existence of a static QName
When must I use elements ?
Marshal:
General content
marshaller.marshal(Object, OutputStream)
must be an element,otherwise the resulting
output is not a legal XML
<xs:any/> Object getAny();void setAny(Object elementOrValue);
<Name>Sharon Krisher</Name><Address>
<Street>Iben Gevirol</Street><Number>57</Number>
</Address>
E.g., when we marshal a PersonType:
Naming
Problem: sometimes XML names are not legal java names do not comply to java naming standards
The binding compiler creates proper names
XML NameClass NameMethod Name
mixedCaseNameMixedCaseNamegetMixedCaseName
name-with-dashNameWithDashgetNameWithDash
aa_bb-ccAaBbCcgetAaBbCc
Java Properties
Local schema components are mapped to: Simple property (get, set)
With customization: isSetName , unsetName List property
Indexed property (next)
java.util.List getAddress();
String getName();void setName(String value);
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"/>
List getAny();
Each item can be some element or
value
Simple Types (partial diagram)SimpleType
Primtive List Union Restriction
ID/IDREF
maxInclusive
Enumeration
date
integer
int
Calendar
BigInteger
int
String/Object
ListRepresented as validation constraints
Next (1)
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 SystemAny
SimpleType ComplexType
SimpleContent ComplexContent Sequence Choice All
Extension Extension
RestrictionAttributes
use default fixed
Elements
abstract nillable minOccurs maxOccurs
finishedRepresented as a Java interface
The interface extends the base type’s interface Represented as
Java properties
*
* *
( ) Next*
**
*
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
interface InternationalPrice {int getValue();void setValue(int);
String getCurrency();void setCurrency(String);
}
<xs:complexType name=“InternationalPrice"> <xs:simpleContent> <xs:extension base="xs:int"> <xs:attribute name="currency“ type="xs:string"/> </xs:extension> </xs:simpleContent></xs:complexType>
Complex Type: Aggregation
<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>
interface Foo { int getA(); void setA(int); int getB(); void setB(int); int getC(); void setC(int); }
<xs:element name="A" type="xs:int"/>
<xs:complexType name="Foo"> <xs:sequence> <xs:element ref="A"/>
<xs:element ref="B"/> <xs:element ref="C"/>
</xs:sequence></xs:complexType>
Complex Type: Mixed Content
<xs:complexType name=“LetterBody" mixed="true"> <xs:sequence> <xs:element name="name" type="xs:string"/> … </xs:sequence></xs:complexType>
interface LetterBody { interface Name extends Element { String getValue(); void setValue(String); } … List getContent();}
Dear Mr.<name>Robert Smith</name>, …
XML fragment
The list may contain elements and strings
LetterBody lb = ObjectFactory.createLetterBody();List gcl = lb.getContent();gcl.add("Dear Mr.");gcl.add(ObjectFactory.createLetterBodyName("Robert Smith"));
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>
public interface FooBarType { Object getFooOrBar(); void setFooOrBar(Object);}
Common supertype of (Integer, String) is ObjectSimilar to union
public interface FooBarType { int getFoo(); void setFoo(int value); String getBar(); void setBar(String value); boolean isSetFoo(); void unsetFoo(); boolean isSetBar(); void unsetBar();}
The programmer is responsible to only set one of Foo or Bar
Default
Customization (Not implemented yet)
When maxOccurs>1
public interface FooBarType { interface Foo extends Element {…} interface Bar extends Element {…} // Items are instances of Foo and Bar List getFooOrBar();}
<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>
For a sequence: List getFooAndBar()The programmer needs to make sure thatthe 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):
XML
Objects in
memoryXML
≠
unmarshal
marshal
Nillable elements
<xs:element name=“age" type=“xs:int" nillable="true"/>
Integer getAge();void setAge(Integer value);
<age xsi:nil="true"/>XML: <age>25</age> or
setAge(null)Java: setAge( new Integer(25) ) or
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.”
42obj.setAge(42);
obj.unsetAge();
System.out.println( obj.getAge() );
Question: What is the output ?
obj.setFoo(42);obj.setBar("A");System.out.println( obj.isSetFoo() );
xs:choice between Foo and Bartrue
Top Related