Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring-boot return json and xml from controllers

Tags:

I have a spring-boot 1.1.7 application that uses Thymeleaf for much of the UI, so the response from my controllers hasn't really been a concern. However, now I need to provide a XML response when a user submits a request via URL.

Here is a typical Request:

http://localhost:9001/remote/search?sdnName=Victoria&address=123 Maple Ave 

Here is most of my gradle configuration:

project.ext {     springBootVersion = '1.1.7.RELEASE' }  dependencies {     compile("org.springframework.boot:spring-boot-starter-web:$springBootVersion")     compile("org.springframework.boot:spring-boot-starter-thymeleaf")     compile("org.springframework.boot:spring-boot-starter-security")     compile("org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion")     compile("org.springframework.security:spring-security-web:4.0.0.M1")     compile("org.springframework.security:spring-security-config:4.0.0.M1")     compile('org.thymeleaf.extras:thymeleaf-extras-springsecurity3:2.1.1.RELEASE')     compile("org.springframework.boot:spring-boot-starter-actuator")     compile('com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.5.0') } 

And here is my controller:

@Controller public class RemoteSearchController {      @Autowired     private SdnSearchService sdnSearchService;      @RequestMapping(value = "/remote/search", method = RequestMethod.GET, produces = MediaType.APPLICATION_XML_VALUE)     public List<Sdn> search(@ModelAttribute SdnSearch sdnSearch) {         List<Sdn> foundSdns = sdnSearchService.find( sdnSearch );         return foundSdns; } 

Here is my Object to be returned:

@Entity public class Sdn {      @Id     private long entNum;     private String sdnName; ... //getters & setters here } 

I am able to receive the request via REST client (such as CocoaREST) and handle it. But When I return the list of SDN i get the following exception, even though I do have Jackson & jackson-dataformat-xml on my classpath:

org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation     at org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.handleNoMatch(RequestMappingInfoHandlerMapping.java:229)     at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.lookupHandlerMethod(AbstractHandlerMethodMapping.java:301)     at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:248)     at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:57)     at org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:299) 

My REST Client is including a Accept Header of "text/xml" (but in all honesty I would rather them not have to set this. Ideally any call to this Controller would always get XML, regardless of header being present).

Is there a way to handle this? I thought the Media Converters were included and just returned whatever the controller told them to?

SOLUTION: See below for the answer I posted.

like image 410
sonoerin Avatar asked Jan 06 '15 02:01

sonoerin


People also ask

CAN REST API return XML?

Data types that REST API can return are as follows: JSON (JavaScript Object Notation) XML. HTML.

Can we exchange XML and JSON data format in rest webservices?

The same resource may return either XML or JSON depending upon the request, but it shouldn't return both at the same time. You will know which one to return based upon the request, so there is no need to generate both -- just generate the one you'll be returning.


2 Answers

I had the exact same problem and I found the solution on Spring documentation website : here

In synthesis, I added the following dependency to the pom.xml of my project :

<dependency>      <groupId>com.fasterxml.jackson.dataformat</groupId>      <artifactId>jackson-dataformat-xml</artifactId>  </dependency> 

Then I added the following code block to the class that the service had to return :

 import javax.xml.bind.annotation.XmlRootElement;   @XmlRootElement  public class Greeting {...} 

And it worked.

like image 186
Mickael Avatar answered Sep 22 '22 12:09

Mickael


SOLUTION: I used a combination of both answers below (thank you very much!). I am posting here in case anyone else needs help.

My modified controller:

@Controller public class RemoteSearchController {      @Autowired     private SdnSearchService sdnSearchService;      @RequestMapping(value = "/remote/search", method = RequestMethod.GET, produces = { "application/xml", "text/xml" }, consumes = MediaType.ALL_VALUE )     @ResponseBody     public SdnSearchResults search(@ModelAttribute SdnSearch sdnSearch) {         List<Sdn> foundSdns = sdnSearchService.find( sdnSearch );         SdnSearchResults results = new SdnSearchResults();         results.setSdns( foundSdns );         return results;     } } 

And on my client, I set the request headers:

Content-type: application/text Accept: text/xml I think ultimately the problem was that my client headers were not being set correctly, so I may not have had to make some of these changes. But I liked the idea of a SearchResults class containing a list of results:

@XmlRootElement public class SdnSearchResults {     private List<Sdn> sdns; ... } 
like image 40
sonoerin Avatar answered Sep 18 '22 12:09

sonoerin