Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HashMap JAXB mapping using @XmlAnyElement

Tags:

java

jaxb

I'm trying to realize an XML mapping involving an HashMap. Here is my use case : I want to get this :

<userParameters>
    <KEY_1>VALUE_1</KEY_1>
    <KEY_2>VALUE_2</KEY_2>
    <KEY_3>VALUE_3</KEY_3>
</userParameters>

My UserParameters class looks like this :

@XmlRootElement
public class UserParameters {

    private final Map<QName, String> params = new HashMap<>();

    @XmlAnyElement
    public Map<QName, String> getParams() {
        return params;
    }

}

I get the following error while marshalling :

Caused by: javax.xml.bind.JAXBException: class java.util.HashMap nor any of its super class is known to this context.
    at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getBeanInfo(JAXBContextImpl.java:593)
    at com.sun.xml.bind.v2.runtime.property.SingleReferenceNodeProperty.serializeBody(SingleReferenceNodeProperty.java:109)
    ... 54 more

It works fine with @XmlAnyAttribute and I get : <userParameters KEY_1="VALUE_1" ... />

From the answers I saw, it seems like I have to make my own XmlAdapter but it feels like overkill for such a simple and common need.

--- UPDATE ---

I found a promising solution here : JAXB HashMap unmappable

The only inconvenient is that it seems to mess up the namespaces.

Here is my new UserParameters class :

@XmlAnyElement
public List<JAXBElement> getParams() {
    return params;
}

public void addParam(String key, String value) {
    JAXBElement<String> element = new JAXBElement<>(new QName(key), String.class, value);
    this.params.add(element);
}

And here is what I get in my XML output :

<params:userParameters>
    <KEY_1 xmlns="" xmlns:ns5="http://url.com/wsdl">
        VALUE_1
    </KEY_1>
</params:userParameters>

I have no idea why JAXB is declaring a namespace in the KEY_1 element.

like image 259
Matt Avatar asked Nov 10 '22 15:11

Matt


1 Answers

@XmlAnyAttribute vs @XmlAnyElement

With attributes it is clear that the map key is the attribute name and that the map value is the attribute value. With elements it is not so clear, the map key could be the element name, but what is the value the entire element? What happens if the key and the value don't match.

Mapping this Use Case

You need to use an XmlAdapter for this use case. Below is an example of how it can be done using EclipseLink JAXB (MOXy), I'm the MOXy lead:

  • http://blog.bdoughan.com/2013/06/moxys-xmlvariablenode-using-maps-key-as.html
like image 120
bdoughan Avatar answered Nov 15 '22 07:11

bdoughan