Accepting / Returning XML / JSON Request and Response - Spring MVC

I need to write a recreation service that accepts XML / JSON as input (POST method) and XML / JSON as output (based on input format). I tried using the approach below, but didn't help. The Endpoint method accepts as XML / JSON, but it always yields either JSON or XML based on the order specified in @RequestMapping -produces. Any help would be really appreciated.

My final method:

@RequestMapping(value = "/getxmljson", method = RequestMethod.POST,produces={"application/json","application/xml"}, consumes={"application/json", "application/xml"}) public @ResponseBody Student processXMLJsonRequest(@RequestBody Student student) throws Exception { System.out.println("*************Inside Controller"); return student; } 

POJO Class: Student.java

 import java.io.Serializable; import java.util.ArrayList; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlType; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonPropertyOrder; @XmlRootElement(name = "student") @XmlType(propOrder = {"id", "name", "graduationTime", "courses"}) @JsonPropertyOrder({"id", "name", "graduationTime", "courses"}) public class Student implements Serializable { private static final long serialVersionUID = 1L; private int id; private String name; private String graduationTime; private ArrayList<Course> courses = new ArrayList<Course>(); @XmlElement public int getId() { return id; } @XmlElement public String getName() { return name; } @XmlElement public String getGraduationTime() { return graduationTime; } @XmlElement public ArrayList<Course> getCourses() { return courses; } public void setId(int value) { this.id = value; } public void setName(String value) { this.name = value; } public void setGraduationTime(String value) { this.graduationTime = value; } public void setCourses(ArrayList<Course> value) { this.courses = value; } @JsonIgnore public String toString() { return this.name + " - " + graduationTime == null? "Unknown" : graduationTime.toString(); } public Student() {} public Student(int id, String name, String graduationTime) { this.id = id; this.name = name; this.graduationTime = graduationTime; } } 

POJO Class: Course.java

 import java.io.Serializable; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlType; import com.fasterxml.jackson.annotation.JsonPropertyOrder; @XmlRootElement(name = "course") @XmlType(propOrder = {"courseName", "score"}) @JsonPropertyOrder({"courseName", "score"}) public class Course implements Serializable { private static final long serialVersionUID = 1L; private String courseName; private Integer score; public @XmlElement String getCourseName() { return courseName; } public @XmlElement Integer getScore() { return score; } public void setCourseName(String value) { courseName = value; } public void setScore(Integer value) { score = value; } public Course() {} public Course(String courseName, Integer score) { this.courseName = courseName; this.score = score; } } 

spring -config.xml

 <?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:sws="http://www.springframework.org/schema/web-services" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:oxm="http://www.springframework.org/schema/oxm" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/web-services http://www.springframework.org/schema/web-services/web-services-2.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-4.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd"> <!-- DispatcherServlet Context: defines this servlet request-processing infrastructure --> <!-- Enables the Spring MVC @Controller programming model --> <annotation-driven /> <!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory --> <resources mapping="/resources/**" location="/resources/" /> <!-- Configure to plugin JSON as request and response in method handler --> <beans:bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"> <beans:property name="messageConverters"> <beans:list> <beans:ref bean="jsonMessageConverter" /> <beans:ref bean="xmlMessageConverter" /> </beans:list> </beans:property> </beans:bean> <!-- Configure bean to convert JSON to POJO and vice versa --> <beans:bean id="jsonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> </beans:bean> <beans:bean id="xmlMessageConverter" class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"> </beans:bean> <beans:bean id="restTemplate" class="org.springframework.web.client.RestTemplate"> </beans:bean> <beans:bean id="objectMapper" class="com.fasterxml.jackson.databind.ObjectMapper" /> <context:component-scan base-package="com.test" /> </beans:beans> 

Json Input:

 { "id":2014, "name":"test", "graduationtime":"09/05/2014", "courses":[ { "courseName":"Math", "score":150 }, { "courseName":"Che", "score":150 } ] } 

XML input:

 <?xml version="1.0" encoding="UTF-8" ?> <student> <id>2014</id> <name>test</name> <graduationTime>09/05/2014</graduationTime> <courses> <courseName>Math</courseName> <score>150</score> </courses> <courses> <courseName>Che</courseName> <score>150</score> </courses> </student> 
+10
source share
5 answers

The best practice for processing different data formats using the same controller is to allow the framework to do all the work of defining the marshalling and decoupling mechanisms.

Step 1 : use the minimum controller configuration

 @RequestMapping(value = "/getxmljson", method = RequestMethod.POST) @ResponseBody public Student processXMLJsonRequest(@RequestBody Student student) { return student; } 

There is no need to specify consumes and produces . As an example, consider that you might want the same method to handle other formats in the future, such as Google protocol buffers, EDI, etc. Saving controllers without consumes and produces will allow you to add data formats through the global configuration instead of changing the controller code.

Step 2 : use ContentNegotiatingViewResolver instead of RequestMappingHandlerAdapter

  <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"> <property name="defaultViews"> <list> <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/> </list> </property> </bean> 

Let the resolving view decide how to read the input data and how to write it.

Step 3 : Use Accepts and Content-Type HTTP Headers

Clicking your controller with the correct HTTP header values ​​will cause the ContentNegotiatingViewResolver automatically marshal and automatically format the data using the appropriate data views.

If you want to exchange data in JSON format, set both headers to application/json . If you want XML instead, set both values ​​to application/xml .

If you don't want to use HTTP headers (which is ideal for you), you can simply add .json or .xml to the URL, and the ContentNegotiatingViewResolver will do the rest.


You can check out my sample application that I created using code snippets that are great for JSON and XML.

+19
source

Adding the answer to Manish above, if you do not want to use the xml based configuration, use this java based configuration -

 @Bean public ViewResolver contentNegotiatingViewResolver() { ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver(); List<View> views = new ArrayList<>(); views.add(new MappingJackson2XmlView()); views.add(new MappingJackson2JsonView()); resolver.setDefaultViews(views); return resolver; } 
+7
source

Register a filter that intercepts each request, warps the HttpServletRequest into an implementation of HttpServletRequestWrapper and returns the Content-Type value for the Accept header. For example, you can register a filter named SameInSameOutFilter as follows:

 @Component public class SameInSameOutFilter extends GenericFilterBean { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { SameInSameOutRequest wrappedRequest = new SameInSameOutRequest((HttpServletRequest) request); chain.doFilter(wrappedRequest, response); } } 

It transfers the current request to SameInSameOutRequest :

 public class SameInSameOutRequest extends HttpServletRequestWrapper { public SameInSameOutRequest(HttpServletRequest request) { super(request); } @Override public String getHeader(String name) { if (name.equalsIgnoreCase("accept")) { return getContentType(); } return super.getHeader(name); } } 

This shell tells spring mvc to select an HttpMessageConverter based on a Content-Type request. If the body of the Content-Type request is application/xml , then the response will be XML . Otherwise, the response will be JSON .

Another solution is to manually set the Accept header along with the Content-Type in each request and avoid all these hacks.

0
source

I faced the same problem as you. Below is my solution and sample.

The following is a maven dependency that you must enable:

  <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.4.3</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.4.3</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.4.3</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> <version>2.4.3</version> </dependency> 

dispatcher-servlet.xml

 <mvc:annotation-driven content-negotiation-manager="contentManager" /> <bean id="contentManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean"> <property name="favorPathExtension" value="false" /> <property name="ignoreAcceptHeader" value="false" /> <property name="defaultContentType" value="application/json" /> <property name="useJaf" value="false" /> </bean> 

and my @RequestMapping (you can use your own request mapping)

 @RequestMapping(value = "/testXMLJSON", method = RequestMethod.GET, produces = { MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE }) @ResponseBody public ArtworkContentMessageType testXMLJSON() { //this is GS1 xml standard mapping. ArtworkContentMessageType resp = new ArtworkContentMessageType(); StandardBusinessDocumentHeader standarBusinessDocumentHeader = new StandardBusinessDocumentHeader(); resp.setStandardBusinessDocumentHeader(standarBusinessDocumentHeader ); ArtworkContentType artWorkContent = new ArtworkContentType(); resp.getArtworkContent().add(artWorkContent); return resp ; } 

If application/xml is required, bottom headers should be present

 Content-Type:application/xml Accept:application/xml 
0
source

If the resource is defined as below

 @GET @Path("/{id}") @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Student getStudent(@PathParam("id") String id) { return student(); // logic to retunrs student object } 

Then the request should contain the header "accept" ("application / json" or application / xml "),
then it returns the response in json or xml format.

Sample request:

 curl -k -X GET -H "accept: application/json" "https://172.17.0.5:8243/service/1.0/222" 

Student class sample

 import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement(name = "student") public class Student { private int id; private String name; private String collegeName; private int age; @XmlAttribute public int getId() { return id; } public void setId(int id) { this.id = id; } @XmlElement public String getName() { return name; } public void setName(String name) { this.name = name; } @XmlElement public String getCollegeName() { return collegeName; } public void setCollegeName(String collegeName) { this.collegeName = collegeName; } public int getAge() { return age; } @XmlElement public void setAge(int age) { this.age = age; } } 
0
source