XML-Schema Support
Juneau provides the {@link oaj.xmlschema.XmlSchemaSerializer} class for generating XML-Schema
documents that describe the output generated by the {@link oaj.xml.XmlSerializer} class.
This class shares the same properties as XmlSerializer.
Since the XML output differs based on settings on the XML serializer class, the XML-Schema serializer
class must have the same property values as the XML serializer class it's describes.
To help facilitate creating an XML Schema serializer with the same properties as the corresponding
XML serializer, the {@link oaj.xml.XmlSerializer#getSchemaSerializer()} method
has been added.
XML-Schema requires a separate file for each namespace.
Unfortunately, does not mesh well with the Juneau serializer architecture which serializes to single writers.
To get around this limitation, the schema serializer will produce a single output, but with multiple
schema documents separated by the null character ('\u0000') to make it simple to split apart.
Lets start with an example where everything is in the same namespace.
We'll use the classes from before, but remove the references to namespaces.
Since we have not defined a default namespace, everything is defined under the default Juneau namespace.
@Bean(typeName="person")
public class Person {
// Bean properties
public String name;
@Swap(TemporalCalendarSwap.IsoInstant.class) public Calendar birthDate;
public List<Address> addresses;
// Getters/setters omitted
}
@Bean(typeName="address")
public class Address {
// Bean properties
public String street, city;
public StateEnum state;
public int zip;
public boolean isCurrent;
// Getters/setters omitted
}
The code for creating our POJO model and generating XML Schema is shown below:
// Create a new serializer with readable output.
XmlSerializer s = XmlSerializer.create()
.ws()
.ns()
.sq()
.addNamespaceUrisToRoot(true)
.build();
// Create the equivalent schema serializer.
XmlSchemaSerializer ss = s.getSchemaSerializer();
// Get the XML Schema corresponding to the XML generated above.
String xmlSchema = ss.serialize(new Person());
<schema
xmlns='http://www.w3.org/2001/XMLSchema'
targetNamespace='http://www.apache.org/2013/Juneau'
elementFormDefault='qualified'
xmlns:juneau='http://www.apache.org/2013/Juneau'>
<element name='person' _type='juneau:org.apache.juneau.examples.addressbook.Person'/>
<complexType name='org.apache.juneau.examples.addressbook.Person'>
<sequence>
<element name='name' _type='string' minOccurs='0'/>
<element name='birthDate' _type='juneau:java.util.Calendar' minOccurs='0'/>
<element name='addresses' _type='juneau:java.util.LinkedList_x003C_org.apache.juneau.examples.addressbook.Address_x003E_' minOccurs='0'/>
</sequence>
</complexType>
<complexType name='java.util.Calendar'>
<sequence>
<any processContents='skip' maxOccurs='unbounded' minOccurs='0'/>
</sequence>
</complexType>
<complexType name='java.util.LinkedList_x003C_org.apache.juneau.examples.addressbook.Address_x003E_'>
<sequence>
<choice minOccurs='0' maxOccurs='unbounded'>
<element name='address' _type='juneau:org.apache.juneau.examples.addressbook.Address'/>
<element name='null' _type='string'/>
</choice>
</sequence>
</complexType>
<complexType name='org.apache.juneau.examples.addressbook.Address'>
<sequence>
<element name='street' _type='string' minOccurs='0'/>
<element name='city' _type='string' minOccurs='0'/>
<element name='state' _type='string' minOccurs='0'/>
<element name='zip' _type='integer' minOccurs='0'/>
<element name='isCurrent' _type='boolean' minOccurs='0'/>
</sequence>
</complexType>
</schema>
Now if we add in some namespaces, we'll see how multiple namespaces are handled.
@Xml(prefix="per")
@Bean(typeName="person")
public class Person {
// Bean properties
public String name;
@Swap(TemporalCalendarSwap.IsoInstant.class) public Calendar birthDate;
public List<Address> addresses;
// Getters/setters omitted
}
@Xml(prefix="addr")
@Bean(typeName="address")
public class Address {
// Bean properties
@Xml(prefix="mail") public String street, city;
@Xml(prefix="mail") public StateEnum state;
@Xml(prefix="mail") public int zip;
public boolean isCurrent;
// Getters/setters omitted
}
The schema consists of 4 documents separated by a '\u0000' character.
<schema
xmlns='http://www.w3.org/2001/XMLSchema'
targetNamespace='http://www.apache.org/2013/Juneau'
elementFormDefault='qualified'
xmlns:juneau='http://www.apache.org/2013/Juneau'
xmlns:per='http://www.apache.org/person/'
xmlns:addr='http://www.apache.org/address/'
xmlns:mail='http://www.apache.org/mail/'>
<import namespace='http://www.apache.org/person/' schemaLocation='per.xsd'/>
<import namespace='http://www.apache.org/address/' schemaLocation='addr.xsd'/>
<import namespace='http://www.apache.org/mail/' schemaLocation='mail.xsd'/>
<complexType name='int'>
<simpleContent>
<extension base='integer'/>
</simpleContent>
</complexType>
<complexType name='java.lang.String'>
<simpleContent>
<extension base='string'/>
</simpleContent>
</complexType>
<complexType name='java.net.URI'>
<simpleContent>
<extension base='string'/>
</simpleContent>
</complexType>
<complexType name='java.util.Calendar'>
<sequence>
<any processContents='skip' maxOccurs='unbounded' minOccurs='0'/>
</sequence>
</complexType>
<complexType name='java.util.LinkedList_x003C_org.apache.juneau.examples.addressbook.Address_x003E_'>
<sequence>
<choice minOccurs='0' maxOccurs='unbounded'>
<element name='address' _type='addr:org.apache.juneau.examples.addressbook.Address'/>
<element name='null' _type='string'/>
</choice>
</sequence>
</complexType>
<complexType name='boolean'>
<simpleContent>
<extension base='boolean'/>
</simpleContent>
</complexType>
</schema>
[\u0000]
<schema
xmlns='http://www.w3.org/2001/XMLSchema'
targetNamespace='http://www.apache.org/person/'
elementFormDefault='qualified'
attributeFormDefault='qualified'
xmlns:juneau='http://www.apache.org/2013/Juneau'
xmlns:per='http://www.apache.org/person/'
xmlns:addr='http://www.apache.org/address/'
xmlns:mail='http://www.apache.org/mail/'>
<import namespace='http://www.apache.org/2013/Juneau' schemaLocation='juneau.xsd'/>
<import namespace='http://www.apache.org/address/' schemaLocation='addr.xsd'/>
<import namespace='http://www.apache.org/mail/' schemaLocation='mail.xsd'/>
<element name='person' _type='per:org.apache.juneau.examples.addressbook.Person'/>
<complexType name='org.apache.juneau.examples.addressbook.Person'>
<sequence>
<any minOccurs='0' maxOccurs='unbounded'/>
</sequence>
<attribute name='uri' _type='string'/>
</complexType>
<element name='name' _type='juneau:java.lang.String'/>
<element name='birthDate' _type='juneau:java.util.Calendar'/>
<element name='addresses' _type='juneau:java.util.LinkedList_x003C_org.apache.juneau.examples.addressbook.Address_x003E_'/>
</schema>
[\u0000]
<schema
xmlns='http://www.w3.org/2001/XMLSchema'
targetNamespace='http://www.apache.org/address/'
elementFormDefault='qualified'
attributeFormDefault='qualified'
xmlns:juneau='http://www.apache.org/2013/Juneau'
xmlns:per='http://www.apache.org/person/'
xmlns:addr='http://www.apache.org/address/'
xmlns:mail='http://www.apache.org/mail/'>
<import namespace='http://www.apache.org/2013/Juneau' schemaLocation='juneau.xsd'/>
<import namespace='http://www.apache.org/person/' schemaLocation='per.xsd'/>
<import namespace='http://www.apache.org/mail/' schemaLocation='mail.xsd'/>
<complexType name='org.apache.juneau.examples.addressbook.Address'>
<sequence>
<any minOccurs='0' maxOccurs='unbounded'/>
</sequence>
</complexType>
<element name='isCurrent' _type='juneau:boolean'/>
</schema>
[\u0000]
<schema
xmlns='http://www.w3.org/2001/XMLSchema'
targetNamespace='http://www.apache.org/mail/'
elementFormDefault='qualified'
attributeFormDefault='qualified'
xmlns:juneau='http://www.apache.org/2013/Juneau'
xmlns:per='http://www.apache.org/person/'
xmlns:addr='http://www.apache.org/address/'
xmlns:mail='http://www.apache.org/mail/'>
<import namespace='http://www.apache.org/2013/Juneau' schemaLocation='juneau.xsd'/>
<import namespace='http://www.apache.org/person/' schemaLocation='per.xsd'/>
<import namespace='http://www.apache.org/address/' schemaLocation='addr.xsd'/>
<element name='street' _type='juneau:java.lang.String'/>
<element name='city' _type='juneau:java.lang.String'/>
<element name='state' _type='juneau:java.lang.String'/>
<element name='zip' _type='juneau:int'/>
</schema>
For convenience, the {@link oaj.xmlschema.XmlSchemaSerializer
#getValidator(SerializerSession,Object)} method is provided to create a
{@link javax.xml.validation.Validator} using the input from the serialize method.