Perhaps when you were a child, you dreamed of one day being big. Perhaps you would lie in the warm summer sun, bare toes dangling in a lazy stream, daydreaming that even you, yes, you, one day could encounter someone who might solve that core, universal human mystery of how to create value object wrapper classes in Java from XML Schemas defining simple content types using custom inline bindings in JAX-B 2.0.
Oh, lucky day...
So. You have a value object defined in an XML Schema that
you want to create as a full-blown object when creating Java objects from JAX-B 2.0. By default, JAX-B will substitute simple types where it can.
USPhone is such a class for me. My schema for USPhone is like this:
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://ns.my.com"
xmlns:x="http://ns.my.com">
<annotation>
<documentation xml:lang="en">
United States phone number, restricted with parens and hyphens optional.
</documentation>
</annotation>
<simpleType name="USPhone">
<restriction base="string">
<pattern value="\(?[2-9]\d\d\)?[ -]?[2-9]\d\d-\d{4}" />
<minLength value="10" />
<maxLength value="16" />
</restriction>
</simpleType>
</schema>
So it's really just a String, and JAX-B knows that, and as a consequence doesn't generate a whole class for it; callers just see that property as a String.
It can be confusing, because even if your referencing schema (say, Customer) holds a phone value that you define as
<complexType name="Customer">
<sequence>
<element name="homePhone" type="x:USPhone" minOccurs="0" maxOccurs="1"/>
...
...at generation time, your beautiful x:USPhone type will be lost to the ravages of JAX-B type simplification. The enclosing Customer object will just hold a string for homePhone.
But what if you don't want that simplification, and do want a whole class generated, considering that you went all that trouble defining the bloody USPhone.xsd in the first place?
This is very easy to turn on and off in JAX-B. You can do it with an internal or external annotation to your calling schema. This is the money shot:
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://ns.my.com"
xmlns:x="http://ns.my.com"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
jxb:version="1.0">
<annotation>
<documentation xml:lang="en">
Represents a Customer...
</documentation>
<appinfo>
<jxb:globalBindings mapSimpleTypeDef="true" />
</appinfo>
</annotation>
The mapSimpleTypeDef attribute is set to false by default, which means that JAX-B will just generate your painstakingly-defined type to whatever it wraps, such as String, if it can.
Setting it to true means that you will get a full blown class generated for your schema type.
I do not get to keep my regular expression here, but it will create a value object like that looks like this:
/**
* <p>Java class for USPhone simple type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* <simpleType name="USPhone">
* <restriction base="{http://www.w3.org/2001/XMLSchema}string">
* <pattern value="\(?[2-9]\d\d\)?[ -]?[2-9]\d\d-\d{4}"/>
* <minLength value="10"/>
* <maxLength value="16"/>
* </restriction>
* </simpleType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "USPhone", propOrder = {
"value"
})
public class USPhone {
@XmlValue
protected String value;
/**
* Gets the value of the value property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getValue() {
return value;
}
/**
* Sets the value of the value property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setValue(String value) {
this.value = value;
}
}
This is what I want for my particular use case and setup.
If you want to specify such exciting JAX-B binding customizations and more, you might want to check out this tutorial: http://java.sun.com/webservices/docs/2.0/tutorial/doc/JAXBUsing4.html.
Be careful, though, because it is about an earlier version of JAX-B, and some things are no longer valid. For example, this has been removed:
<jxb:globalBindings bindingStyle="modelGroupBinding"/>
Argh.
On a related matter, it's up for debate whether internal (inline) or external binding directives are better. They work either way. I've shown the inline version here for brevity and clarity.
Inline customizations have the advantage of being easy to use, requiring no modification of your Ant script or XJC task if you change them or take them out altogether.
They have a disadvantage inasmuch as they "pollute" your otherwise pure XML Schemas with not only Java-specific code, but JAX-B specific code. While it's not going to kill anybody who might be using Python instead of Java, it's generally a bad practice to expose implementations like this.
Keeping your binding customizations in an external bindings file is appealing aesthetically. It achieves our usual goal of high cohesion--that one file does just that one thing. It keeps our schemas fresh for porting everything to .NET later if we want. It has the disadvantage of being a little harder to set up, but that's a one-time hit.
One issue with both of them of course is the same as with any customization: if you change implemenations later (say, to Castor), your binding customizations are now invalid, even though your schema isn't. So be very clear as to what your implementations depend on, and what you really have control over.
Good luck.
Comments