Spring-boot return json and xml from controllers
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.
It may be better to create a new class:
public class SdnSearchResult {
private List<Sdn> sdns;
...
}
Then, a slight change will be required to the existing classes as follows:
public interface SdnSearchService {
SdnSearchResult find(SdnSearch sdnSearch);
}
@Controller
public class UISearchController {
@Autowired
private SdnSearchService sdnSearchService;
@RequestMapping("/search")
public ModelAndView search(@ModelAttribute SdnSearch sdnSearch) {
return new ModelAndView("pages/search/results", "sdns", sdnSearchService.find(sdnSearch).getSdns());
}
}
Once this is done, the other controller must be coded as:
@Controller
public class RemoteSearchController {
@Autowired
private SdnSearchService sdnSearchService;
@RequestMapping("/remote/search")
@ResponseBody
public SdnSearchResult search(@RequestBody SdnSearch sdnSearch) {
return sdnSearchService.find(sdnSearch);
}
}
A quick explanation of the changes from your code:
@RequestBody
will automatically deserialize the entire HTTP request body to anSdnSearch
instance. External applications will typically submit the request data as HTTP body, so@RequestBody
will ensure that the deserialization to Java object happens automatically.@ResponseBody
will automatically serialize the return value according to the external client's capabilities and the libraries available on the classpath. If Jackson is available on the classpath and the client has indicated that they can accept JSON, the return value will be automatically sent as JSON. If the JRE is 1.7 or higher (which means that JAXB is included with the JRE) and the client has indicated that they can accept XML, the return value will be automatically sent as XML.List<Sdn>
needs to be changed toSdnSearchResult
to ensure that the application can exchange JSON, XML, RSS and ATOM formats with a single controller method, since XML (and XML based formats) require a root-tag on the output, which aList<Sdn>
cannot be translated to.
Once these changes are done, fire up a REST client such as the Postman extension for Chrome and submit a request to /remote/search
with the following information:
- Request header
Accepts
set toapplication/json
. - Request header
Content-Type
set toapplication/json
. - Request body set to the JSON string
{ "sdnName" : "Victoria", "address" : "123 Maple Ave" }
.
This will give you a JSON response.
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;
...
}