andyb
andyb

Reputation: 43823

@XmlElements and @XmlJavaTypeAdapter not working together

I'm having a small problem with JAXB unmarshalling in that my input XML can be wrapped by one of two elements, for example:

<Output>
  <Update>
      <Channel>
          <id>1</id>
      </Channel>
      <Channel>
          <id>2</id>
      </Channel>
  </Update>
</Output>

or

<Output>
  <Erase>
      <Channel>
          <id>1</id>
      </Channel>
  </Erase>
</Output>    

My root class is unmarshalling the Channels to a HashMap using an @XmlJavaTypeAdapter and the code below works as expected.

@XmlRootElement(name="Output")
public class Output{
    @XmlElement(name="Update")
    @XmlJavaTypeAdapter(ChannelAdapter.class)
    private HashMap<Long, Channel> allChannels;
    public Map getChannels() {
        return allChannels;
    }
}

where Channels class is:

public class Channels {
    @XmlElement(name="Channel")
    public Channel[] channels;
}

and the Channel is:

@XmlAccessorType(XmlAccessType.FIELD)
public class Channel {
    @XmlPath("id/text()")
    private Long id;
}

and finally the ChannelAdapter is:

public class ChannelAdapter extends XmlAdapter<Channels, Map<Long, Channel>> {
    @Override
    public Map<Long, Channel> unmarshal(Channels value) { ... }

    @Override
    public Channels marshal(Map<Long, Channel> map) { ... }
}

However I thought I could just replace @XmlElement(name="Update") with

@XmlElements({
    @XmlElement(name="Update"),
    @XmlElement(name="Erase")
})

but that results in an empty map.

Hard-coding to either @XmlElement(name="Update") or @XmlElement(name="Erase") works with one or other the input XML documents but I need something that will work with either of the wrapper elements. I tried using a @XmlElementWrapper but that can only be used on a collection or array property which will not work since allChannels is a HashMap.

Could I please get an explain of what am I misunderstanding about the @XmlElements annotation and also a way to get this working? Thanks!

Upvotes: 3

Views: 1251

Answers (2)

draculine
draculine

Reputation: 11

Try to change your XSDs to something that let's Output incorporate a choice allowing the XML to use either of the elements but never ever both at the same time.

I don't know, however, how to annotate this via XmlElements. Try to build an XSD first an then generate the classes for looking up the annotations ;).

Upvotes: 1

yves amsellem
yves amsellem

Reputation: 7234

As far as I know, JAXB forces you to have a bidirectional data model; you cannot merge two children of a node into one without breaking this convention. So, you need to have two lists, one for Updates and one for Erases.

Because I've never used @XmlElements annotation, take my comment with care.

Upvotes: 1

Related Questions