I wasn't so far from the answer - after a bit more of experimenting I found the right combo.
Create a wrapper class for the un-mapable return type. Wrapper should contain/return List<JAXBElement<String>
Annotate wrapper return type with @XmlAnyElement
.
public class MapWrapper {
@XmlAnyElement
public List<JAXBElement<String>> properties = new ArrayList<JAXBElement<String>>();
}
Create an XmlAdapter that marshals to the MapWrapper
public class MapAdapter extends XmlAdapter<MapWrapper, Map<String,String>> {
@Override
public MapWrapper marshal(Map<String,String> m) throws Exception {
MapWrapper wrapper = new MapWrapper();
List<JAXBElement<String>> elements = new ArrayList<JAXBElement<String>>();
for (Map.Entry<String, String> property: m.entrySet()) {
elements.add(new JAXBElement<String>(
new QName(getCleanLabel(property.getKey())),
String.class, property.getValue()));
}
wrapper.elements=elements;
return wrapper;
}
@Override
public Map<String,String> unmarshal(MapWrapper v) throws Exception {
// TODO
throw new OperationNotSupportedException();
}
// Return a lower-camel XML-safe attribute
private String getCleanLabel(String attributeLabel) {
attributeLabel = attributeLabel.replaceAll("[()]", "")
.replaceAll("[^\w\s]", "_").replaceAll(" ", "_")
.toUpperCase();
attributeLabel = CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL,
attributeLabel);
return attributeLabel;
}
}
Annotate your unmappable type with the XmlAdapter
@XmlRootElement
public class SomeBean {
@XmlJavaTypeAdapter(MapAdapter.class)
public LinkedHashMap<String, String> getProperties() {
return properties;
}
}
A map like:
My Property 1 My Value 1
My Property 2 My Value 2
Should come out as:
<someBean>
<properties>
<myProperty1>My Value 1</myProperty1>
<myProperty2>My Value 1</myProperty2>
</properties>
</someBean>
Hope this helps someone else!
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…