prev | table of contents | next |
XmlJavaTypeAdapter
For some Java container types JAXB has no built-in mapping to an XML
structure. Also, you may want to represent Java types in a way that is
entirely different from what JAXB is apt to do. Such mappings require an
adapter class, written as an extension of
XmlAdapter<XmlType,ApplType>
from the package
javax.xml.bind.annotation.adapters
. The annotation
XmlJavaTypeAdapter
is provided for announcing the adapter
in the desired place.
We'll illustrate adapters by defining a substitution of a map for an array. Here is an XML example of the data we have to deal with.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <ns:training xmlns:ns="http://foo/bar"> <brochure> <course price="123.45" id="c1"> <name>Course 1</name> </course> <course price="123.45" id="c0"> <name>Course 0</name> </course> </brochure> </ns:training>The
course
elements could be represented as a list or array,
but we would like to process this data in our application as a map of the
id
attribute to the Course
object. Although JAXB
is capable of handling maps, we have seen (in section
Top-level Elements:
XmlRootElement
) that the resulting XML structure
isn't as simple as possible. To achieve our goal, we write a class
Brochure
containing the map we have in mind and declare
that this is the one that has to be adapted to something JAXB knows
how to handle, i.e., the class Courses
containing a
simple array of Course
objects.
@XmlRootElement(name="training") public class Training { @XmlElement public Brochure brochure; public Training(){} public Training( Brochure b ){ brochure = b; } } @XmlJavaTypeAdapter(BrochureAdapter.class) public class Brochure { Map<String,Course> courses; public Brochure() { courses = new HashMap<String, Course>(); } } public class Courses { @XmlElement(name="course") public Course[] carray; } public class Course { @XmlAttribute String id; @XmlElement String name; @XmlAttribute Price price; }Class
Brochure
is annotated with XmlJavaTypeAdapter
,
defining class BrochureAdapter
as its adapter, and this
is, of course, the interesting class. It has to
override methods unmarshal
and marshal
.
public class BrochureAdapter extends XmlAdapter<Courses,Brochure> { @Override public Brochure unmarshal( Courses value ){ Brochure b = new Brochure(); for( Course c : value.carray ) b.courses.put( c.id, c ); return b; } @Override public Courses marshal( Brochure b ){ Courses courses = new Courses(); Collection<Course> c = b.courses.values(); courses.carray = c.toArray(new Course[c.size()]); return courses; } }
Courses
is a class JAXB knows how to handle with respect
to XML data, and the result of JAXB's innate capabilities is passed
to the adaption for unmarshalling. In this method, we convert the
data to a structure according to the desired class Brochure
with its map. The reverse marshalling process has to convert a
Brochure
object with its map to a Courses
object, which is easily done by putting the map values into an array.
To summarize: XML binding happens against the class Courses
,
whereas application programming uses the Map
type field
courses
in class Brochure
.
prev | table of contents | next |