Jackson xml and json root element

12,837

The JSON and XML structures are not equivalent. In XML you want a list of RestObject and in JSON you want a list whose elements wrap instances of RestObject in another object. This isn't something you can get with a simple Jackson annotation, you would need a custom serializer only for JSON serialization. First of all, getting the desired XML format is straightforward:

class RestObject implements Serializable {
    private LocalDateTime timestamp;
    private String title;
    private String fullText;
    private Long id;
    private Double value;
}

@JsonRootName("restObjectList")
class RestObjectList {
    @JacksonXmlProperty(localName = "restObject")
    @JacksonXmlElementWrapper(useWrapping = false)
    private List<RestObject> restObjectList;
}

If you absolutely want to wrap each element in the array in json you'll need a custom serializer e.g.

class RestObjectSerializer extends JsonSerializer<RestObject> {
    @Override
    public void serialize(RestObject value, JsonGenerator gen, SerializerProvider serializers) throws
            IOException {
        gen.writeStartObject();
        gen.writeObjectFieldStart("restObject");
        gen.writeObjectField("timeStamp", value.getTimestamp());
        gen.writeStringField("title", value.getTitle());
        // other fields
        gen.writeEndObject();
        gen.writeEndObject();
    }
}

And register only with the ObjectMapper that serializes JSON so it doesn't interfere with serialization to XML:

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule("MyModule");
module.addSerializer(RestObject.class, new RestObjectSerializer());
mapper.registerModule(module);
Share:
12,837
Yan Khonski
Author by

Yan Khonski

I have experience building global products used from all over the world. I build simple solutions to complex problems. https://github.com/yan-khonski-it https://www.linkedin.com/in/yan-khonski/ https://leetcode.com/yan-khonski-it/

Updated on June 17, 2022

Comments

  • Yan Khonski
    Yan Khonski almost 2 years

    I have a service which returns objects in JSON and XML format.

    http://localhost:8091/apiN/xml/2

    XML Result

    <restObjectList>
        <restObjectList>
            <restObjectList>
                <timestamp>2017-06-19 17:01:01</timestamp>
                <title>Rest object</title>
                <fullText>This is the full text. ID: 1</fullText>
                <id>1</id>
                <value>0.1412789210135622</value>
            </restObjectList>
            <restObjectList>
                <timestamp>2017-06-19 17:01:01</timestamp>
                <title>Rest object</title>
                <fullText>This is the full text. ID: 2</fullText>
                <id>2</id>
                <value>0.9886539664938628</value>
            </restObjectList>
        </restObjectList>
    </restObjectList>
    

    http://localhost:8091/apiN/2

    JSON result

    {
        "restObjectList": [
            {
                "timestamp": "2017-06-19 17:01:01",
                "title": "Rest object",
                "fullText": "This is the full text. ID: 1",
                "id": 1,
                "value": 0.1412789210135622
            },
            {
                "timestamp": "2017-06-19 17:01:01",
                "title": "Rest object",
                "fullText": "This is the full text. ID: 2",
                "id": 2,
                "value": 0.9886539664938628
            }
        ]
    }
    

    Result I'd like to receive

    xml

    <restObjectList>
        <restObject>
            <timestamp>2017-06-19 17:01:01</timestamp>
            <title>Rest object</title>
            <fullText>This is the full text. ID: 1</fullText>
            <id>1</id>
            <value>0.1412789210135622</value>
        </restObject>
        <restObject>
            <timestamp>2017-06-19 17:01:01</timestamp>
            <title>Rest object</title>
            <fullText>This is the full text. ID: 2</fullText>
            <id>2</id>
            <value>0.9886539664938628</value>
        </restObject>
    </restObjectList>
    

    json

    {
        "restObjectList": [{
            "restObject": {
                "timestamp": "2017-06-19 17:01:01",
                "title": "Rest object",
                "fullText": "This is the full text. ID: 1",
                "id": 1,
                "value": 0.1412789210135622
            }
        }, {
            "restObject": {
                "timestamp": "2017-06-19 17:01:01",
                "title": "Rest object",
                "fullText": "This is the full text. ID: 2",
                "id": 2,
                "value": 0.9886539664938628
            }
        }]
    }
    

    How do I wrap restObject for JSON and XML and fix XML data for restObjectList because this tag is repeated at different levels.

    My code

    RestObject

    @JsonRootName(value = "restObject")
    @XmlRootElement(name = "restObject")
    public class RestObject implements Serializable {
    
        private LocalDateTime timestamp;
        private String title;
        private String fullText;
        private Long id;
        private Double value;
    
        //Getters, setters
    }
    

    RestObjectList

    @JsonRootName(value = "restObjectList")
    @XmlSeeAlso({RestObject.class})
    public class RestObjectList {
    
        private List<RestObject> restObjectList;
    
        //Getter and setter
    }
    

    JacksonConfig

    @Configuration
    public class JacksonConfig {
    
        @Bean
        public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
            ObjectMapper objectMapper = builder.createXmlMapper(true).build();
            objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);//Use custom date-time format.
            objectMapper.configure(SerializationFeature.WRAP_ROOT_VALUE, false);
            objectMapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, false);
            return objectMapper;
        }
    
        @Bean
        public ObjectMapper objectMapper() {
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
            objectMapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);
            return objectMapper;
        }
    }