dinup24
dinup24

Reputation: 1772

Jackson: different XML and JSON format

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

Answers (1)

Paul Samsotha
Paul Samsotha

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.


EDIT

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`
}

UPDATE

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

Related Questions