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 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 interface s Source schema JAXB solution: Mapping XML Schema to Java interfaces Pros: preserve types, compile-time checking Cons: complex, specific to a certain schema
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 <xs:element name="Address" type="AddressType" minOccurs="1" maxOccurs="unbounded"/> Demo.xsd
Step 2: Create XML Document <Person xmlns:xsi=" xsi:noNamespaceSchemaLocation="C:\JAXB Demo\demo.xsd"> Sharon Krisher Iben Gevirol 57 Moshe Sharet 89 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 PersonType public 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 Must contain at least one item Must be non-negative 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")); Yoav Zibin Hanoter 5 output.xml
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 When is the difference important? (next) … 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 Object getAny(); void setAny(Object elementOrValue); Sharon Krisher Iben Gevirol 57 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
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: List getAny(); Each item can be some element or value
Simple Types (partial diagram) SimpleType Primtive ID/IDREF date integer int ListUnionRestriction maxInclusiveEnumeration Calendar BigInteger int String/Object List Represented as validation constraints Next (1) Next (2)
Simple Type: Union Public interface Date { Object getMonth(); void setMonth(Object); } Common supertype of ( Integer, String ) is Object
Type Safe Enumeration 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 SimpleTypeComplexType SimpleContent Extension ComplexContent Extension Restriction SequenceChoiceAll Attributes use default fixed Elements abstract nillable minOccurs maxOccurs finished Represented 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); }
Complex Type: Aggregation interface Foo { int getA(); void setA(int); int getB(); void setB(int); int getC(); void setC(int); }
Complex Type: Mixed Content … interface LetterBody { interface Name extends Element { String getValue(); void setValue(String); } … List getContent(); } Dear Mr. Robert Smith, … 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 public interface FooBarType { Object getFooOrBar(); void setFooOrBar(Object); } Common supertype of ( Integer, String ) is Object Similar 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(); } For a sequence: List getFooAndBar() The programmer needs to make sure that the list contains sequences of.
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 memory XML ≠ unmarshal marshal
Nillable elements Integer getAge(); void setAge(Integer value); XML: 25 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 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.” 42 obj.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 Bar true
The END Any questions?