Manuel Jordan Manuel Jordan - 3 months ago 59
reST (reStructuredText) Question

Multiple scenarios @RequestMapping produces JSON/XML together with Accept or ResponseEntity

I am working with Spring 4.0.7

About Spring MVC, for research purposes, I have the following:

@RequestMapping(value="/getjsonperson",
method=RequestMethod.GET,
produces=MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody Person getJSONPerson(){
logger.info("getJSONPerson - getjsonperson");
return PersonFactory.createPerson();
}

@RequestMapping(value="/getperson.json", method=RequestMethod.GET)
public @ResponseBody Person getPersonJSON(){
logger.info("getPerson - getpersonJSON");
return PersonFactory.createPerson();
}


Each one works fine, observe both for JSON, with and without extension:


  • /getjsonperson

  • /getperson.json



Same for XML

@RequestMapping(value="/getxmlperson",
method=RequestMethod.GET,
produces=MediaType.APPLICATION_XML_VALUE
)
public @ResponseBody Person getXMLPerson(){
logger.info("getXMLPerson - getxmlperson");
return PersonFactory.createPerson();
}

@RequestMapping(value="/getperson.xml", method=RequestMethod.GET)
@ResponseBody
public Person getPersonXML(){
logger.info("getPerson - getpersonXML");
return PersonFactory.createPerson();
}


Each one works fine, observe both for XML, with and without extension:


  • /getxmlperson

  • /getperson.xml



Now about Restful I have the following:

@RequestMapping(value="/person/{id}/",
method=RequestMethod.GET,
produces={MediaType.APPLICATION_JSON_VALUE,
MediaType.APPLICATION_XML_VALUE})
public ResponseEntity<Person> getPersonCustomizedRestrict(@PathVariable Integer id){
Person person = personMapRepository.findPerson(id);
return new ResponseEntity<>(person, HttpStatus.FOUND);//302
}


Observe the
MediaType
, it is mixed, for JSON and XML

Through RestTemplate I can indicate the
Accept
value

if(type.equals("JSON")){
logger.info("JSON");
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
}
else if(type.equals("XML")){
logger.info("XML");
headers.setAccept(Arrays.asList(MediaType.APPLICATION_XML));
}
….

ResponseEntity<Person> response =
restTemplate.exchange("http://localhost:8080/spring-utility/person/{id}/customizedrestrict",
HttpMethod.GET,
new HttpEntity<Person>(headers),
Person.class,
id
);


Until here, therefore I am able to use one URL/URI to get some data in either XML or JSON formats. It works fine

My problem is with Spring MVC … just consider

@RequestMapping(value="/{id}/person",
method=RequestMethod.GET,
produces={MediaType.APPLICATION_JSON_VALUE,
MediaType.APPLICATION_XML_VALUE})
public @ResponseBody Person getPerson(@PathVariable Integer id){
return personMapRepository.findPerson(id);
}


I can call or activate that handler method (
@RequestMapping
) through:


  1. jQuery working with Ajax, I am able to indicate the
    Accept
    value (JSON for example)

  2. Poster, through the
    Headers
    button, I can set the
    Accept



Question One:

But for a common link? how I can set the
Accept
value? is possible?

I thought in other way to around this problem.


  • http://localhost:8080/spring-utility/person/getpersonformat?format=json

  • http://localhost:8080/spring-utility/person/getpersonformat?format=xml



Observe:


  • ?format



Therefore

@RequestMapping(value="/getpersonformat",
method=RequestMethod.GET,
produces={MediaType.APPLICATION_JSON_VALUE,
MediaType.APPLICATION_XML_VALUE})
public @ResponseBody Person getPerson(@RequestParam String format){
return personMapRepository.findPerson(id);
}


Question Two:

What code for the method shown above must be added to customize the return type format?
I mean, JSON or XML, Is possible?

I thought in the following:

@RequestMapping(value="/getpersonformataltern",
method=RequestMethod.GET
produces={MediaType.APPLICATION_JSON_VALUE,
MediaType.APPLICATION_XML_VALUE}
)
public ResponseEntity<Person> getPersonFormat(@RequestParam String format){
logger.info("getPersonFormat - format: {}", format);
HttpHeaders httpHeaders = new HttpHeaders();
if(format.equals("json")){
logger.info("Ok JSON");
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
}
else{
logger.info("Ok XML");
httpHeaders.setContentType(MediaType.APPLICATION_XML);
}
return new ResponseEntity<>(PersonFactory.createPerson(), httpHeaders, HttpStatus.OK);
}


But:

If I execute the URL:


  • http://localhost:8080/spring-utility/person/getpersonformataltern?format=json



I get

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<person>
<id>1</id>
<firstName>Manuel</firstName>
<lastName>Jordan</lastName>

</person>


Yes in XML!

Note: I can confirm the Console prints
Ok JSON


If I execute the URL:


  • http://localhost:8080/spring-utility/person/getpersonformataltern?format=xml



I get

This XML file does not appear to have any style information associated with it.
The document tree is shown below.

<person>
<id>1</id>
<firstName>Manuel</firstName>
<lastName>Jordan</lastName>

</person>


Question Three

What code for the method shown above must be added to fix the JSON output?
I don't know what is wrong or is missing..

There are three questions.

Thank You

Alpha

@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
Map<String,MediaType> mediaTypes = new LinkedHashMap<>();
mediaTypes.put("json", MediaType.APPLICATION_JSON);
mediaTypes.put("xml", MediaType.APPLICATION_XML);
configurer.mediaTypes(mediaTypes);
configurer.defaultContentType(MediaType.TEXT_HTML);
}

Answer

Using Accept header is really easy to get the format json or xml from the REST service.

This is my Controller, take a look produces section.

@RequestMapping(value = "properties", produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE}, method = RequestMethod.GET)
    public UIProperty getProperties() {
        return uiProperty;
    }

In order to consume the REST service we can use the code below where header can be MediaType.APPLICATION_JSON_VALUE or MediaType.APPLICATION_XML_VALUE

HttpHeaders headers = new HttpHeaders();
headers.add("Accept", header);

HttpEntity entity = new HttpEntity(headers);

RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.exchange("http://localhost:8080/properties", HttpMethod.GET, entity,String.class);
return response.getBody();

Edit 01:

In order to work with application/xml, add this dependency

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