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:
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:
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:
Accept
value (JSON for example)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); }
One of the most important annotations in spring is the @RequestMapping Annotation which is used to map HTTP requests to handler methods of MVC and REST controllers. In Spring MVC applications, the DispatcherServlet (Front Controller) is responsible for routing incoming HTTP requests to handler methods of controllers.
RequestMapping annotation is used to map web requests onto specific handler classes and/or handler methods. @RequestMapping can be applied to the controller class as well as methods.
APPLICATION_JSON is a "public constant media type for application/json ", whereas MediaType. APPLICATION_JSON_VALUE is a "String equivalent of MediaType. APPLICATION_JSON ". Attributes on Java annotations can only be one of a limited set of types. This prevents MediaType from being used as an annotation attribute.
The @Produces annotation is used to specify the MIME media types or representations a resource can produce and send back to the client. If @Produces is applied at the class level, all the methods in a resource can produce the specified MIME types by default.
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>
All your problems are that you are mixing content type negotiation with parameter passing. They are things at different levels. More specific, for your question 2, you constructed the response header with the media type your want to return. The actual content negotiation is based on the accept media type in your request header, not response header. At the point the execution reaches the implementation of the method getPersonFormat, I am not sure whether the content negotiation has been done or not. Depends on the implementation. If not and you want to make the thing work, you can overwrite the request header accept type with what you want to return.
return new ResponseEntity<>(PersonFactory.createPerson(), httpHeaders, HttpStatus.OK);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With