Reputation: 1772
In my Apache wink based REST project, we are using Jackson jax-rs providers for handling both JSON and XML content type. Our response object contains a HashMap<String, PropertyObject>
. The map key contains whitespaces and hence it can't be serialized as XML element names. JSON serialization works fine.
JSON format:
{
"properties": {
"a b c": {
"name": "a b c",
"type": "Double",
"value": "2.0"
},
"x y z": {
"name": "x y z",
"type": "Double",
"value": "0.0"
}
}
}
Desired XML format
<rootElement>
<Property name="a b c" type="double" value="2.0">
<Property name="x y z" type="double" value="0.0">
</rootElement>
How can we achieve this using Jackson jax-rs XML and JSON providers. Is it possible to define custom jackson serializers and extend jax-rs providers. Please suggest a best possible approach.
Upvotes: 1
Views: 1668
Reputation: 208984
One way you can change the XML is to use a JAXB XmlAdapter
. Something like
public class PropertyAdapter extends XmlAdapter<PropertyAdapter.AdaptedProperties,
HashMap<String, PropertyObject>> {
public static class AdaptedProperties {
public ArrayList<PropertyObject> property = new ArrayList<>();
}
@Override
public HashMap<String, PropertyObject> unmarshal(
PropertyAdapter.AdaptedProperties list) throws Exception {
HashMap<String, PropertyObject> map = new HashMap<>();
for (PropertyObject prop: list.property) {
map.put(prop.getName(), prop);
}
return map;
}
@Override
public PropertyAdapter.AdaptedProperties marshal(
HashMap<String, PropertyObject> map) throws Exception {
ArrayList<PropertyObject> list = new ArrayList<>(map.values());
AdaptedProperties props = new AdaptedProperties();
props.property = list;
return props;
}
}
Then just annotate the field/property
@XmlRootElement
public class DTO {
private HashMap<String, PropertyObject> properties;
@XmlJavaTypeAdapter(PropertyAdapter.class)
public HashMap<String, PropertyObject> getProperties() {
return properties;
}
// setter
}
This will be the result. It's not exactly how you want it, but I can't figure out how to get it without the <properties>
wrapper.
<root>
<properties>
<property name="a b c" type="Double" value="2.0"/>
<property name="x y z" type="Double" value="0.0"/>
</properties>
</root>
One thing you also need to make sure of is that when you are using Jackson, you aren't using the provider that has JAXB annotation support configured. If you use this provider, it will use the XmlAdapter
and you will get a JSON array, instead of an object/map like you currently have. Assuming you are using this provider, it has a JacksonJaxbJsonProvider
and a plain JacksonJsonProvider
. You want to make sure to just register the latter.
Oh and I forgot to add that the PropertyObject
class I used to test looks like this
@XmlRootElement
public class PropertyObject {
private String name;
@XmlAttribute(name = "name")
public String getName() {
return name;
}
// There are `type` and `value` fields also, with corresponding
// getters and setters, both using the `@XmlAttribute`
}
Let's assume you did want the JAXB annotation support for Jackson JSON serialization. What you can do is configure your own ObjectMapper
, and just use the one with JAXB support for this one class. You can see how that is possible here
Upvotes: 2