views:

259

answers:

3

I have the following xml fragment (which is outside of my control):

<item>
  <name>Name</name>
  <category>1</category>
  <subcategory>2</subcategory>
</item>

I'd like <subcategory> to be unmarshalled to a class that looks like this:

public class SubCategory {
  private Category parent;
  private int code;
  private String name;

  public SubCategory(int code, Category parent){
    this.code = code;
    this.parent = parent;
    this.name = lookupName(code);
  }

  // Getters, setters and lookupName(int) here
}

In other words, the object resulting from the <category> tag should be passed to the object resulting from the <subcategory> element.

How can I do this? Is this even possible? I know about XmlAdapter, but I see no way to get hold of the parent.

I'd prefer it if it can be done in the constructor, so an instance can never be in an invalid state, but I'll settle for a different solution, as long as I don't have to manually set the parent for each SubCategory.

A: 

One way I can think of how to do it is write some XSLT that transforms the XML in something easier to map in JAXB. While this will probably work, it's an extra step I'd rather avoid.

Sietse
+2  A: 

JAXB will not do this for you. XmlAdapter is not appropriate for this problem. When the class structure is significantly different to the XML structure, then you'll need to perform an additional level of transformation, either before the JAXB bind (with XSLT), or after the JAXB bind (using Java).

The latter option is much easier. You'll need a class which represents the structure of the XML, and a transformation route which turns instances that bound class in to instances of your desired structure.

skaffman
+2  A: 

You could do this with XMLAdapter if you adapt Item rather than SubCategory.

ItemAdapter.java:

public class ItemAdapter extends XmlAdapter<ItemProxy, Item>
{
    @Override
    public ItemProxy marshal( Item v ) throws Exception
    {
        ItemProxy proxy = new ItemProxy();

        proxy.setCategory( v.getCategory().getCode() );
        proxy.setSubcategory( v.getSubCategory().getCode() );
        proxy.setName( v.getName() );

        return proxy;
    }

    @Override
    public Item unmarshal( ItemProxy v ) throws Exception
    {
        Item item = new Item();

        Category category = new Category( v.getCategory() );
        SubCategory subCategory = new SubCategory( v.getSubcategory(), category );

        item.setName( v.getName() );
        item.setCategory( category );
        item.setSubCategory( subCategory );

        return item;
    }
}

ItemProxy.java:

@XmlRootElement( name = "item" )
public class ItemProxy
{
    private String name;
    private int category;
    private int subcategory;

    @XmlElement
    public String getName()
    {
        return name;
    }

    @XmlElement
    public int getCategory()
    {
        return category;
    }

    @XmlElement
    public int getSubcategory()
    {
        return subcategory;
    }

    public void setName( String name )
    {
        this.name = name;
    }

    public void setCategory( int category )
    {
        this.category = category;
    }

    public void setSubcategory( int subcategory )
    {
        this.subcategory = subcategory;
    }
}
mtpettyp
This only will work if Item isn't the root node - see https://jaxb.dev.java.net/issues/show_bug.cgi?id=117
mtpettyp