users@jaxb.java.net

Re: XmlJavaTypeAdapter help

From: Wolfgang Laun <wolfgang.laun_at_gmail.com>
Date: Sun, 24 Aug 2008 12:05:24 +0200

The annotation on Brochure.courses says that you want to have a
sub-element <course>. Note that nothing here indicates that this
element would have - expressed in XML Schema language -
maxOccurs="unbounded". So there is going to be a single <course>
element. The Course[] that's going to be used for the contents
of <course> needs some intermediary level for separating its
elements - that's why you have the <item>s. In short: I don't think
you're doing anything wrong.

If you do want an XML structure without the additional XML level,
you'll have to let JAXB see a collection, to be marshalled as
Brochure's sub-element, e.g.:

   @XmlElement(name="courses")
   Collection<Course> courses;

Another option would be to adapt Brochure (and not its field). This
doesn't work for Brochure being a root element, but given this
additional class

@XmlRootElement(name="college")
public class College {
    @XmlElement
    public Brochure brochure;

    public College(){}
    public College( Brochure b ){
        brochure = b;
    }
}

you can write Brochure.java as

@XmlJavaTypeAdapter(BrochureAdapter.class)
public class Brochure {
    Map<String,Course> courses;
    public Brochure() {
        courses = new HashMap<String, Course>();
    }
}

BrochureAdapter.java maps a Brochure to a class Courses which informs
JAXB about the desired XML structure:

public class Courses {
    @XmlElement(name="course")
    public Course[] carray;
}

public class BrochureAdapter
extends XmlAdapter<Courses,Brochure> {

    public Brochure unmarshal( Courses value ) {
        Brochure b = new Brochure();
        for( Course c : value.carray )
            b.courses.put( c.id, c );
        return b;
    }

    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;
    }
}

And this is what you'll get now

<college>
    <brochure>
        <course id="c1">
            <name>Course 1</name>
        </course>
        <course id="c0">
            <name>Course 0</name>
        </course>
    </brochure>
</college>

HTH,
Wolfgang


On Sun, Aug 24, 2008 at 4:39 AM, murakris <cme_mk_at_yahoo.com> wrote:
>
> Hi, I'm trying to follow the XmlAdapter example in Koshuke's blog here:
> http://weblogs.java.net/blog/kohsuke/archive/2005/04/xmladapter_in_j.html
>
> and when I try to marshall the Brochure class, it results in xml output like
> this:
> <brochure>
> <course>
> <item id="c0">
> <name>Course 0</name>
> </item>
> <item id="c1">
> <name>Course 1</name>
> </item>
> </course>
> </brochure>
>
> instead of
> <brochure>
> <course id="c0">
> <name>Course 0</name>
> </item>
> <course id="c1">
> <name>Course 1</name>
> </item>
> </brochure>
>
> Can you please help me understand what I'm doing wrong? Below is the rest of
> the code:
>
> Brochure.java:
> @XmlRootElement(name="brochure")
> public class Brochure {
> @XmlJavaTypeAdapter(CourseListAdapter.class)
> @XmlElement(name="course")
> Map<String,Course> courses;
>
> public Brochure() {
> courses = new HashMap<String, Course>();
> }
> }
>
> Course.java
> public class Course {
> @XmlAttribute
> String id;
> @XmlElement
> String name;
> }
>
> CourseListAdapter
> public class CourseListAdapter extends XmlAdapter<Course[],
> Map<String,Course>> {
> public Map<String,Course> unmarshal( Course[] value ) {
> Map<String,Course> r = new HashMap<String,Course>();
> for( Course c : value )
> r.put(c.id,c);
> return r;
> }
> public Course[] marshal( Map<String,Course> value ) {
> return value.values().toArray(new Course[value.size()]);
> }
>
> Test class:
> public class Main {
>
> @Test public void test() throws Exception {
> JAXBContext jc = JAXBContext.newInstance(Brochure.class);
> Marshaller m = jc.createMarshaller();
> m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
>
> Brochure b = new Brochure();
> for (int i=0; i<2; i++) {
> Course c = getCourse(i);
> b.courses.put(c.id, c);
> }
>
> m.marshal(b, System.out);
>
> }
>
> public Course getCourse(int i) {
> Course c1 = new Course();
> c1.id="c" + i;
> c1.name="Course " + i;
> return c1;
> }
> }
>
> }
>
> Thanks in advance!
> Murali