Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring REST with both JSON and XML

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

1) Create both a json and xml controller/model

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

2) Write a custom message converter

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.

3) Let each model object serialize itself, e.g.,

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());
like image 834
Johan Sjöberg Avatar asked Aug 20 '13 12:08

Johan Sjöberg


People also ask

CAN REST API use XML and JSON?

The REST API can use either XML or JSON to encode data sent in requests or received in responses.

How do I accept both JSON and XML in spring boot?

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.

How do I accept different formats in REST services?

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.


1 Answers

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.

like image 136
trebor Avatar answered Sep 20 '22 15:09

trebor