By default, XML Schema types are mapped to Java primitive types. While this is the most logical mapping between XML Schema and Java, it does not always meet the requirements of the application developer. You might want to map an XML Schema primitive type to a Java class that can hold extra information, or you might want to map an XML primitive type to a class that allows for simple type substitution.
The JAXB javaType
customization element allows you to customize the mapping between an
XML Schema primitive type and a Java primitive type. It can be used to customize the mappings at both the global level and the
individual instance level. You can use the javaType
element as part of a simple type definition or
as part of a complex type definition.
When using the javaType
customization element you must specify methods for converting the
XML representation of the primitive type to and from the target Java class. Some mappings have default conversion methods. For
instances where there are no default mappings, FUSE Services Framework provides JAXB methods to ease the development of the required
methods.
The javaType
customization element takes four attributes, as described in
Table 16.1.
Table 16.1. Attributes for Customizing the Generation of a Java Class for an XML Schema Type
Attribute | Required | Description |
---|---|---|
name | Yes | Specifies the name of the Java class to which the XML Schema primitive type is mapped. It must be either a valid Java class name or the name of a Java primitive type. You must ensure that this class exists and is accessible to your application. The code generator does not check for this class. |
xmlType | No | Specifies the XML Schema primitive type that is being customized. This attribute is only used when the javaType element is used as a child of the globalBindings element. |
parseMethod | No | Specifies the method responsible for parsing the string-based XML representation of the data into an instance of the Java class. For more information see Specifying the converters. |
printMethod | No | Specifies the method responsible for converting a Java object to the string-based XML representation of the data. For more information see Specifying the converters. |
The javaType
customization element can be used in three ways:
To modify all instances of an XML Schema primitive type — The javaType
element
modifies all instances of an XML Schema type in the schema document when it is used as a child of the
globalBindings
customization element. When it is used in this manner, you must specify a value
for the xmlType
attribute that identifies the XML Schema primitive type being modified.
Example 16.7 shows an in-line global customization that instructs
the code generators to use java.lang.Integer
for all instances of xsd:short in the
schema.
Example 16.7. Global Primitive Type Customization
<schema targetNamespace="http://widget.com/types/widgetTypes" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="2.0"> <annotation> <appinfo> <jaxb:globalBindings ...> <jaxb:javaType name="java.lang.Integer" xmlType="xsd:short" /> </globalBindings </appinfo> </annotation> ... </schema>
To modify a simple type definition — The javaType
element modifies the class
generated for all instances of an XML simple type when it is applied to a named simple type definition. When using the
javaType
element to modify a simple type definition, do not use the
xmlType
attribute.
Example 16.8 shows an external binding file that modifies the generation of a simple type named zipCode.
Example 16.8. Binding File for Customizing a Simple Type
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xsd="http://www.w3.org/2001/XMLSchema" jaxb:version="2.0"> <jaxb:bindings wsdlLocation="widgets.wsdl"> <jaxb:bindings node="xsd:simpleType[@name='zipCode']"> <jaxb:javaType name="com.widgetVendor.widgetTypes.zipCodeType" parseMethod="com.widgetVendor.widgetTypes.support.parseZipCode" printMethod="com.widgetVendor.widgetTypes.support.printZipCode" /> </jaxb:bindings> </jaxb:bindings> <jaxb:bindings>
To modify an element or attribute of a complex type definition — The javaType
can
be applied to individual parts of a complex type definition by including it as part of a JAXB property customization. The
javaType
element is placed as a child to the property's baseType
element. When using the javaType
element to modify a specific part of a complex type definition,
do not use the xmlType
attribute.
Example 16.9 shows a binding file that modifies an element of a complex type.
Example 16.9. Binding File for Customizing an Element in a Complex Type
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xsd="http://www.w3.org/2001/XMLSchema" jaxb:version="2.0"> <jaxb:bindings schemaLocation="enumMap.xsd"> <jaxb:bindings node="xsd:ComplexType[@name='widgetOrderInfo']"> <jaxb:bindings node="xsd:element[@name='cost']"> <jaxb:property> <jaxb:baseType> <jaxb:javaType name="com.widgetVendor.widgetTypes.costType" parseMethod="parseCost" printMethod="printCost" > </jaxb:baseType> </jaxb:property> </jaxb:bindings> </jaxb:bindings> </jaxb:bindings> <jaxb:bindings>
For more information on using the baseType
element see
Specifying the Base Type of an Element or an Attribute.
The FUSE Services Framework cannot convert XML Schema primitive types into random Java classes. When you use the
javaType
element to customize the mapping of an XML Schema primitive type, the code generator
creates an adapter class that is used to marshal and unmarshal the customized XML Schema primitive type. A sample adapter
class is shown in Example 16.10.
Example 16.10. JAXB Adapter Class
public class Adapter1 extends XmlAdapter<String,javaType
> { publicjavaType
unmarshal(String value) { return(parseMethod(value)
); } public String marshal(javaType
value) { return(printMethod(value)
); } }
parseMethod
and printMethod
are replaced by the value of
the corresponding parseMethod
attribute and printMethod
attribute.
The values must identify valid Java methods. You can specify the method's name in one of two ways:
A fully qualified Java method name in the form of
packagename
.ClassName
.methodName
A simple method name in the form of methodName
When you only provide a simple method name, the code generator assumes that the method exists in the class specified by the javaType
element's name
attribute.
![]() | Important |
---|---|
The code generators do not generate parse or print methods. You are responsible for supplying them. For information on developing parse and print methods see Implementing converters. |
If a value for the parseMethod
attribute is not provided, the code generator assumes that the
Java class specified by the name
attribute has a constructor whose first parameter is a Java
String
object. The generated adapter's unmarshal()
method uses
the assumed constructor to populate the Java object with the XML data.
If a value for the printMethod
attribute is not provided, the code generator assumes that the
Java class specified by the name
attribute has a toString()
method. The generated adapter's marshal()
method uses the assumed
toString()
method to convert the Java object to XML data.
If the javaType
element's name
attribute specifies a Java primitive type, or one of the Java primitive's wrapper types, the code generators use the default converters. For more information on default converters see Default primitive type converters.
As mentioned in Specifying the converters, using the
javaType
customization element triggers the generation of one adapter class for each customization
of an XML Schema primitive type. The adapters are named in sequence using the pattern
Adapter
. If you specify two primitive type customizations, the code
generators create two adapter classes: N
Adapter1
and Adapter2
.
The code generated for an XML schema construct depends on whether the effected XML Schema construct is a globally defined element or is defined as part of a complex type.
When the XML Schema construct is a globally defined element, the object factory method generated for the type is modified from the default method as follows:
The method is decorated with an @XmlJavaTypeAdapter
annotation.
The annotation instructs the runtime which adapter class to use when processing instances of this element. The adapter class is specified as a class object.
The default type is replaced by the class specified by the javaType
element's
name
attribute.
Example 16.11 shows the object factory method for an element affected by the customization shown in Example 16.7.
Example 16.11. Customized Object Factory Method for a Global Element
@XmlElementDecl(namespace = "http://widgetVendor.com/types/widgetTypes", name = "shorty") @XmlJavaTypeAdapter(org.w3._2001.xmlschema.Adapter1 .class) public JAXBElement<Integer> createShorty(Integer value) { return new JAXBElement<Integer>(_Shorty_QNAME, Integer.class, null, value); }
When the XML Schema construct is defined as part of a complex type, the generated Java property is modified as follows:
The property is decorated with an @XmlJavaTypeAdapter
annotation.
The annotation instructs the runtime which adapter class to use when processing instances of this element. The adapter class is specified as a class object.
The property's @XmlElement
includes a type
property.
The value of the type property is the class object representing the generated object's default
base type. In the case of XML Schema primitive types, the class is String
.
The property is decorated with an @XmlSchemaType
annotation.
The annotation identifies the XML Schema primitive type of the construct.
The default type is replaced by the class specified by the javaType
element's
name
attribute.
Example 16.12 shows the object factory method for an element affected by the customization shown in Example 16.7.
Example 16.12. Customized Complex Type
public class NumInventory {
@XmlElement(required = true, type = String.class)
@XmlJavaTypeAdapter(Adapter1 .class)
@XmlSchemaType(name = "short")
protected Integer numLeft;
@XmlElement(required = true)
protected String size;
public Integer getNumLeft() {
return numLeft;
}
public void setNumLeft(Integer value) {
this.numLeft = value;
}
public String getSize() {
return size;
}
public void setSize(String value) {
this.size = value;
}
}
The FUSE Services Framework runtime has does not know how to convert XML primitive types to and from the Java class specified by the
javaType
element, except that it should call the methods specified by the
parseMethod
attribute and the printMethod
attribute. You are
responsible for providing implementations of the methods the runtime calls. The implemented methods must be capable of working
with the lexical structures of the XML primitive type.
To simplify the implementation of the data conversion methods, FUSE Services Framework provides the
javax.xml.bind.DatatypeConverter
class. This class provides methods for parsing and printing all of the
XML Schema primitive types. The parse methods take string representations of the XML data and they return an instance of the
default type defined in Table 12.1. The print methods take an instance of the default type
and they return a string representation of the XML data.
The Java documentation for the DatatypeConverter
class can be found at
http://java.sun.com/webservices/docs/1.6/api/javax/xml/bind/DatatypeConverter.html.
When specifying a Java primitive type, or one of the Java primitive type Wrapper classes, in the
javaType
element's name
attribute, it is not necessary to specify
values for the parseMethod
attribute or the printMethod
attribute.
The FUSE Services Framework runtime substitutes default converters if no values are provided.
The default data converters use the JAXB DatatypeConverter
class to parse the XML data. The
default converters will also provide any type casting necessary to make the conversion work.