The Java EE 5 Tutorial

XmlAdapter Field Example

The XmlAdapter Field example demonstrates how to use the XmlAdapter interface and the @XmlJavaTypeAdapter annotation to provide a custom mapping of XML content into and out of a HashMap (field) that uses an int as the key and a String as the value.

Interface XmlAdapter and annotation @XmlJavaTypeAdapter are used for special processing of data types during unmarshalling/marshalling. There are a variety of XML data types for which the representation does not map easily into Java (for example, xs:DateTime and xs:Duration), and Java types which do not map conveniently into XML representations, for example implementations of java.util.Collection (such as List) and java.util.Map (such as HashMap) or for non-JavaBean classes.

The XmlAdapter interface and the @XmlJavaTypeAdapter annotation are provided for cases such as these. This combination provides a portable mechanism for reading/writing XML content into and out of Java applications.

The XmlAdapter interface defines the methods for data reading/writing.

/*
 *  ValueType - Java class that provides an XML representation
 *              of the data. It is the object that is used for
 *              marshalling and unmarshalling.
 *
 *  BoundType - Java class that is used to process XML content.
 */
public abstract class XmlAdapter<ValueType,BoundType> {
    // Do-nothing constructor for the derived classes.
    protected XmlAdapter() {}
    // Convert a value type to a bound type.
    public abstract BoundType unmarshal(ValueType v);
    // Convert a bound type to a value type.
    public abstract ValueType marshal(BoundType v);
 }

You can use the @XmlJavaTypeAdapter annotation to associate a particular XmlAdapter implementation with a Target type, PACKAGE, FIELD, METHOD, TYPE, or PARAMETER.

The XmlAdapter Field example shows how to use an XmlAdapter for mapping XML content into and out of a (custom) HashMap. The HashMap object, basket, in class KitchenWorldBasket, uses a key of type int and a value of type String. These data types should be reflected in the XML content that is read and written, so the XML content should look like this.

<basket>
     <entry key="9027">glasstop stove in black</entry>
     <entry key="288">wooden spoon</entry>
</basket>

The default schema generated for Java type HashMap does not reflect the desired format.

<xs:element name="basket">
   <xs:complexType>
     <xs:sequence>
       <xs:element name="entry" minOccurs="0" maxOccurs="unbounded">
         <xs:complexType>
           <xs:sequence>
             <xs:element name="key" minOccurs="0" type="xs:anyType"/>
             <xs:element name="value" minOccurs="0" type="xs:anyType"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
  </xs:complexType>
</xs:element>

In the default HashMap schema, key and value are both elements and are of data type anyType. The XML content will look like this:

<basket>
     <entry>
        <key>9027</>
        <value>glasstop stove in black</>
     </entry>
     <entry>
        <key>288</>
        <value>wooden spoon</>
    </entry>
</basket>

To resolve this issue, the example uses two Java classes, PurchaseList and PartEntry, that reflect the needed schema format for unmarshalling/marshalling the content. The XML schema generated for these classes is as follows:

<xs:complexType name="PurchaseListType">
    <xs:sequence>
        <xs:element name="entry" type="partEntry"
            nillable="true" maxOccurs="unbounded"
            minOccurs="0"/>
    </xs:sequence>
</xs:complexType>
<xs:complexType name="partEntry">
    <xs:simpleContent>
        <xs:extension base="xs:string">
            <xs:attribute name="key" type="xs:int"
                use="required"/>
        </xs:extension>
    </xs:simpleContent>
</xs:complexType>

Class AdapterPurchaseListToHashMap implements the XmlAdapter interface. In class KitchenWorldBasket, the @XmlJavaTypeAdapter annotation is used to pair AdapterPurchaseListToHashMap with field HashMap basket. This pairing will cause the marshal/unmarshal method of AdapterPurchaseListToHashMap to be called for any corresponding marshal/unmarshal action on KitchenWorldBasket.

Building and Running the XmlAdapter Field Example Using NetBeans IDE

Follow these instructions to build and run the XmlAdapter Field example on your Application Server instance using the NetBeans IDE.

  1. In NetBeans IDE, select File->Open Project.

  2. In the Open Project dialog, navigate to tut-install/javaeetutorial5/examples/jaxb/.

  3. Select the j2s-xmlAdapter-field folder.

  4. Select the Open as Main Project check box.

  5. Click Open Project.

  6. Right-click the j2s-xmlAdapter-field project and select Run.

Building and Running the XmlAdapter Field Example Using Ant

To compile and run the XmlAdapter Field example using Ant, in a terminal window, go to the tut-install/javaeetutorial5/examples/jaxb/j2s-xmlAdapter-field/ directory and type the following:


ant runapp