I want to provide one comprehensive REST API with support for both JSON
and XML
.
The domain model is of complex type and we note that to produce friendly JSON
and XML
on the same model using MappingJacksonHttpMessageConverter
and JaxbMarshaller
respectively tends to give either readable XML or readable JSON 1).
What's the best way to proceed?
1) Due to how objects such as maps, root tags and relations are modelled differently in json
than in xml
, the objects to serialize needs to be designed differently to get both tidy json
and tidy xml
. Utilities such as jaxb annotations only goes that far.
I can think of a few candidates
public class Controller {
public Foo foo() {
return new Foo();
}
}
public class XmlController extends Controller {
@Override
public XmlFoo foo() {
return new new XmlFoo(super.foo());
}
}
public class JsonController extends Controller {
@Override
public JsonFoo foo() {
return new JsonFoo(super.foo());
}
}
Given a model object Foo
create a JsonFoo
and XmlFoo
I tried this and it turned out to be a bit complicated since the view must know how to resolve e.g., a Foo
to a JsonFoo
to be able to serialize it into a readable format.
public class Foo {
public String serialize(Serializer s) {
return s.serialize(this);
}
}
Based on some arbitration parameter let the controller inject the correct serializer
new Foo(new FooJsonSerializer());
new Foo(new FooXmlSerializer());
The REST API can use either XML or JSON to encode data sent in requests or received in responses.
Implementing XML Representation for Spring Boot Services Restart your application. Send a request to http://localhost:8080/students/10001 with Accept header as 'application/xml'. Cool! Your application now supports both XML and JSON representations of the student resource.
To indicate your preferred data format for response data (for all requests), indicate the format by setting the HTTP Accept header on the request. For clients without the ability to set HTTP headers, use the accept query parameter to indicate your preferred format, for example accept=application/json.
I'm doing this in a current project without using a ContentNegotiatingViewResolver
. For one method in my controller:
@RequestMapping(value = "/test", method = RequestMethod.GET)
@ResponseBody
public HttpEntity<BasicResponse> getBasicResponse() {
return new HttpEntity<BasicResponse>(new BasicResponse());
}
I can receive the following output based on the Accept
request header.
Accept: application/xml (requires JAXB2 on the classpath)
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<basicResponse>
<errors>
<message>test1</message>
<message>test2</message>
</errors>
</basicResponse>
Accept: application/json (requires Jackson on the classpath)
{
"errors" : ["test1", "test2"]
}
My response object is simple and uses normal annotations:
package org.mypackage.response;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class BasicResponse {
@XmlElementWrapper(name = "errors")
@XmlElement(name = "message")
private List<String> errors = new ArrayList<String>();
public BasicResponse() {
this.errors.add("test1");
this.errors.add("test2");
}
public List<String> getErrors() {
return errors;
}
}
The SpringSource spring-mvc-showcase project is also a helpful resource. I think they separate the conversions for different methods, but I am definitely doing this for one method.
I can't quite tell by your question...but if you're looking to serialize the output more than that, @chrylis is correct in that a custom serializer would be your next move. But everything I've ran into (which can get pretty complex, with nested objects in my response) converts perfectly to valid XML or JSON.
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