Level: Intermediate Russell Butek (butek@us.ibm.com), IT Specialistt, IBM Nicholas Gallardo (nlgallar@us.ibm.com), Staff Software Engineer, IBM
30 Nov 2006 JAX-WS 2.0, the successor to JAX-RPC 1.1, has evolved its data mapping methods by using JAXB (the Java Architecture for XML Binding), a JCP-defined technology. This second tip in a series compares the data mappings of these two Web services specifications. Read Part 1 of JAX-RPC vs. JAX-WS for a broader look at their differences.
Introduction
While some aspects of JAX-WS 2.0 are merely evolutionary to JAX-RPC 1.1, other parts are revolutionary. For example, JAX-WS does not provide mapping between XML schema and Java, a major feature of JAX-RPC 1.1. Instead, JAX-WS uses another JCP-defined technology, JAXB (the Java Architecture for XML Binding) 2.0, to do its data mapping for it. JAX-WS simply represents the invocation model for Web services. It no longer concerns itself with the Java Beans that represent application data; it only focuses on delivering them to the target Web service. Here, we'll compare JAX-RPC 1.1 and the JAXB 2.0 mappings.
Mapping XML schema to Java
 |
JAX-RPC and JAXB
Why didn't JAX-RPC use JAXB in the first place? The answer is timing. The first version of JAX-RPC was completed before JAXB, so rather than wait, the writers of JAX-RPC developed their own mapping feature.
|
|
Mapping XML names to Java names in JAX-RPC and JAX-WS/JAXB are essentially the same, while mapping simple types has some slight differences. Table 1 shows these differences, which may appear significant; however, except for date/time types, they're the least-used XML simple types.
Table 1. Mapping differences between JAX-RPC 1.1 and JAXB 2.0 for XML simple types
| Type | JAX-RPC 1.1 | JAXB 2.0 |
|---|
| xsd:anySimpleType | java.lang.String | java.lang.Object | | xsd:duration | java.lang.String | javax.xml.datatype.Duration (new type) | | xsd:dateTime | java.util.Calendar | javax.xml.datatype.XMLGregorianCalendar (new type) | | xsd:time | java.util.Calendar | javax.xml.datatype.XMLGregorianCalendar | | xsd:date | java.util.Calendar | javax.xml.datatype.XMLGregorianCalendar | | xsd:gYearMonth | java.lang.String | javax.xml.datatype.XMLGregorianCalendar | | xsd:gYear | java.lang.String | javax.xml.datatype.XMLGregorianCalendar | | xsd:gMonthDay | java.lang.String | javax.xml.datatype.XMLGregorianCalendar | | xsd:gMonth | java.lang.String | javax.xml.datatype.XMLGregorianCalendar | | xsd:gDay | java.lang.String | javax.xml.datatype.XMLGregorianCalendar | | xsd:anyURI | java.net.URI | java.lang.String | | xsd:NMTOKENS | java.lang.String[] | java.util.List<java.lang.String> | | xsd:IDREF | java.lang.String | java.lang.Object | | xsd:IDREFS | java.lang.String[] | java.util.List<java.lang.Object> | | xsd:ENTITY | not supported | java.lang.String | | xsd:ENTITIES | not supported | java.util.List<java.lang.String> |
The pure Java aspects of the simple type mappings are nearly the same between JAX-RPC and JAXB, but the JAXB mappings also use the new Java annotation feature. See Listings 1 through 3 for some examples of simple type mappings.
Listing 1. XML complexType elements and attributes
<xsd:sequence>
<xsd:element name="intField" type="xsd:int"/>
<xsd:element name="intMinField" type="xsd:int" minOccurs="0"/>
<xsd:element name="intNilField" type="xsd:int" nillable="true"/>
<xsd:element name="stringField" type="xsd:string"/>
<xsd:element name="stringMinField" type="xsd:string" minOccurs="0"/>
<xsd:element name="stringNilField" type="xsd:string" nillable="true"/>
</xsd:sequence>
<xsd:attribute name="intAttr" type="xsd:int"/>
<xsd:attribute name="intAttrReq" type="xsd:int" use="required"/>
|
Listing 2. Mapping to Java Bean properties via JAX-RPC 1.1
private int intField;
private Integer intMinField;
private Integer intNilField;
private String stringField;
private String stringMinField;
private String stringNilField;
private Integer intAtt;
private int intAttReq;
|
Listing 3. Mapping to Java Bean properties via JAXB 2.0
protected int intField;
protected Integer intMinField;
@XmlElement(required = true, type = Integer.class, nillable = true)
protected Integer intNilField;
@XmlElement(required = true)
protected String stringField;
protected String stringMinField;
@XmlElement(required = true, nillable = true)
protected String stringNilField;
@XmlAttribute
protected Integer intAtt;
@XmlAttribute(required = true)
protected int intAttReq;
|
In a JAX-RPC 1.1-generated Java Bean, you cannot tell the difference between:
- An element field and an attribute field
- A field mapped from
minOccurs="0" type="xsd:int" and a field mapped from nillable="true" type="xsd:int"
- A field mapped from
type="xsd:string" and type="xsd:string" minOccurs="0"
But now you can, thanks to JAXB's use of new Java annotations. The @XmlElement and @XmlAttribute annotations have several parameters. The ones pertinent to this article include:
- Required: Must the element exist? For example, is
minOccurs something other than one?
- Nillable: Does the field contain the
nillable="true" attribute?
Mapping arrays
Mapping arrays from XML to Java differs between JAX-RPC and JAXB because JAXB uses the new generic Java feature, as Listings 4 through 6 show.
Listing 4. XML array
<xsd:element name="intArrayField" type="xsd:int" minOccurs="0" maxOccurs="unbounded"/>
|
Listing 5. Mapping to Java Bean properties via JAX-RPC 1.1
private int[] intArrayField;
public int[] getIntArrayField() {...}
public void setIntArrayField(int[] intArrayField) {...}
public int getIntArrayField(int i) {...}
public void setIntArrayField(int i, int value) {...}
|
Listing 6. Mapping to Java Bean properties via JAXB 2.0
@XmlElement(type = Integer.class)
protected List<Integer> intArrayField;
public List<Integer> getIntArrayField() {...}
|
Notice the differences in the accessor methods. The JAX-RPC mapping follows the strict definition of Java Bean array accessors. The JAXB mapping does not map to an array, so it slightly differs. getIntArrayField returns a reference, not just a snapshot, to the live list. Therefore, any modification you make to the returned list will be present inside the property. This is why no set method exists for 'array' properties.
Mapping complex types
Mapping a complexType is nearly the same between JAX-RPC and JAXB, except the fields are private in JAX-RPC and protected in JAXB, and the JAXB mapping adds annotations describing the field order. See Listings 7 through 9 for an example and comparisons between the two mappings.
Listing 7. XML schema complexType
<xsd:element name="Phone" type="tns:Phone"/>
<xsd:complexType name="Phone">
<xsd:sequence>
<xsd:element name="areaCode" type="xsd:string"/>
<xsd:element name="exchange" type="xsd:string"/>
<xsd:element name="number" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
|
Listing 8. JAX-RPC 1.1 mapping of complexType
public class Phone {
private String areaCode;
private String exchange;
private String number;
...
} |
Listing 9. JAXB 2.0 mapping of complexType
@XmlType(name = "Phone", propOrder = {
"areaCode",
"exchange",
"number"
})
public class Phone {
@XmlElement(required = true)
protected String areaCode;
@XmlElement(required = true)
protected String exchange;
@XmlElement(required = true)
protected String number;
...
} |
Note that the schema in Listing 7 used xsd:sequence. If it had used xsd:all instead, the propOrder annotation would have been empty: @XmlType(name = "Phone", propOrder = {}).
The new ObjectFactory class
JAXB generates a file that JAX-RPC does not: ObjectFactory. Each directory containing Java Beans will have one ObjectFactory. For each type defined in the schema's corresponding namespace, the ObjectFactory class will have a create method for that type. For each element, the ObjectFactory class will have a create element method, which returns a javax.xml.bind.JAXBElement<Type>. For example, for the Phone schema in Listing 7, Listing 10 shows the generated ObjectFactory class with a method that returns an instance of Phone and a method that returns an instance of JAXBElement<Phone>. You can still directly instantiate the Java Beans in the directory, but it would be best to use the factory.
Listing 10. JAXB 2.0 ObjectFactory for Phone
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlElementDecl;
import javax.xml.namespace.QName;
public class ObjectFactory {
private final static QName _Phone_QNAME = new QName
("urn:types.MyServiceSample.ibm.com", "Phone");
public ObjectFactory() {...}
public Phone createPhone() {...}
@XmlElementDecl(namespace = "urn:types.MyServiceSample.ibm.com", name = "Phone")
public JAXBElement<Phone> createPhone(Phone value) {...}
}
|
Java to XML schema mappings
With a judicious sprinkling of these new JAXB-defined annotations, Java can map in a well-directed manner to XML, essentially in the reverse of the XML-to-Java mappings that we have presented. But what about unannotated Java?
Mapping Java names to XML names in JAX-RPC and JAXB are essentially the same. That is, Java primitive types map to the same XML schema whether the mapping follows JAX-RPC or JAXB. JAX-RPC defines a small set of standard Java classes that map to XML. For all but one of those, JAXB maps precisely the same, but JAXB adds a few more to its list of mapped classes, as Table 2 shows.
Table 2. Mapping differences between JAX-RPC 1.1 and JAXB 2.0 for standard Java classes
| Type | JAX-RPC 1.1 | JAXB 2.0 |
|---|
| java.lang.String | xsd:string | xsd:string | | java.math.BigInteger | xsd:integer | xsd:integer | | java.math.BigDecimal | xsd:decimal | xsd:decimal | | java.util.Calendar | xsd:dateTime | xsd:dateTime | | java.util.Date | xsd:dateTime | xsd:dateTime | | javax.xml.namespace.QName | xsd:QName | xsd:QName | | java.net.URI | xsd:anyURI | xsd:string | | javax.xml.datatype.XMLGregorianCalendar | n/a | xsd:anySimpleType | | javax.xml.datatype.Duration | n/a | xsd:duration | | java.lang.Object | n/a1 | xsd:anyType | | java.awt.Image | n/a2 | xsd:base64Binary | | javax.activation.DataHandler | n/a2 | xsd:base64Binary | | javax.xml.transform.Source | n/a2 | xsd:base64Binary | | java.util.UUID | n/a | xsd:string |
Table 2 Notes:
1. Some vendors mapped java.lang.Object to xsd:anyType.
2. In JAX-RPC, this is mapped to a mime binding type - the XML type is undefined.
Conclusion
We've compared the mappings of JAX-RPC 1.1 and JAXB 2.0. They are similar with some notable exceptions:
- XML to Java:
- A few of the simple types are mapped differently
- JAXB adds the ObjectFactory class
- JAXB makes use of the new Java language annotation feature and generic feature
- Java to XML:
- The primitive type mappings are identical
- The standard Java mappings are nearly identical
We can say much more about the JAXB 2.0 specification, particularly its use of Java annotations, but that topic is out of this article's scope. For more information about JAXB 2.0, see Resources.
Resources
About the authors  | |  | Russell Butek is an IBM SOA and Web services consultant. He has been one of the developers of IBM's WebSphere Web services engine. He has also been a member the JAX-RPC Java Specification Request (JSR) expert group. He was involved in the implementation of Apache's AXIS SOAP engine, driving AXIS 1.0 to comply with JAX-RPC. |
 | |  | Nicholas Gallardo works as a software engineer on the IBM WebSphere Web Services engine, where he is focused on serviceability and interoperability. Nicholas came to IBM in 2001 after contributing development efforts to two different technology start-ups in Austin, Texas. |
原文链接: http://www.ibm.com/developerworks/webservices/library/ws-tip-jaxwsrpc2.html?ca=drs-&ca=dkw-Web%25services%25hints%25and%25tips%25JAX-RPC%25JAX-WS
|