Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jaxb objects with same name

Tags:

java

rest

xml

jaxb

It would appear to be possible to unmarshal two different jaxb objects with the same name.

There is a Bar class ...

public abstract Bar {
   private @XmlElement String val;
}

.. with Two implementations (constructors etc. left out):

@XmlRootElement(name="bar")
public class BarA extends Bar { }

@XmlRootElement(name="bar")
public class BarB extends Bar {
     private @XmlElement(required=true) String type;
}

Lastly I want to unmarshall a list of Bar documents from XML similar to the following

<bars>
  <bar>
    <val>1</val>
  </bar>
  <bar>
    <val>1</val>
    <type>2</type>
  </bar>
</bars>

The list is wrapped in an class utilizing the @XmlAnyElement

@XmlRootElement
public class Bars {

  @XmlMixed
  @XmlAnyElement(lax = true) 
  @XmlElementRefs({@XmlElementRef(BarA.class), @XmlElementRef(BarB.class)})
  private List<Bar> bars;
}

However I seem to only get instances of either BarA or BarB, whichever is the last element in the @XmlElementRefs chain.

Testing code:

String xml = ...
JAXBContext jc = JAXBContext.newInstance(Bars.class);
ByteArrayInputStream in = new ByteArrayInputStream(xml.getBytes());
Bars bars = (Bars) jc.createUnmarshaller().unmarshal(in);
for (Bar bar : bars.getBars()) {
    System.out.println(bar.getClass());
}

I don't think the XmlAdapter suggested in JAXB @XmlElements, different types but same name? would neccesarily be the only approach either.

like image 902
Johan Sjöberg Avatar asked Jan 20 '12 15:01

Johan Sjöberg


2 Answers

Really, the first thing I would try to do is eliminate the source of the problem - having two different JAXB classes with the same name. A situation like that is bound to cause headaches, for you and for the people who have to maintain your code.

If that's impossible... Maybe you could write another subclass called EveryBar, and always unmarshall to that. EveryBar would contain all the fields of every other Bar subclass. Then you'd have a post-processing step on your object tree that would examine the EveryBar, and swap it for an instance of whatever type is appropriate. Yeah, it's an ugly solution, but it's only slightly worse than the one from your link.

like image 66
Mike Baranczak Avatar answered Oct 12 '22 01:10

Mike Baranczak


You could use an XmlAdapter to do this. Below are answers I gave to a similar question:

  • Java/JAXB: Unmarshall XML attributes to specific Java object attributes
  • eclipselink/Moxy : inheritance and attribute name oveloading based on type
like image 20
bdoughan Avatar answered Oct 11 '22 23:10

bdoughan