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;
}
}
A JSON message can have either an anonymous object or an anonymous array as the root of the data. It is not possible to put a JSON string literal, number, boolean, or null value as the root of the data using the JSON parser.
JAXB converts XML to java objects, and Jackson converts the same java objects to JSON.
The Jackson XML module supports the full range of annotations that Jackson provides for annotating our POJOs. This means that we can have one single set of beans, with one set of annotations and, depending on the ObjectMapper instance, we select whether we get XML or JSON.
With XML module Jackson provides support for JAXB (javax. xml. bind) annotations as an alternative to native Jackson annotations, so it is possible to reuse existing data beans that are created with JAXB to read and write XMLs.
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With