We would like to build a REST server with Spring MVC. It should be very simple to support various formats like JSON and XML for the same request, just by changing the Content header. Example, I have the below url:
http://localhost:8090/simple-spring-rest/bank-detail
It should return me either json or xml or some other format depending on the Accept header to application/json or application/xml respectively.
Lets see how to achieve that.
We will use pure Java configuration:
@Configuration @EnableWebMvc @ComponentScan("com.swayam.demo.web.rest") @PropertySource("classpath:jdbc.properties") public class WebConfig extends WebMvcConfigurerAdapter { @Override public void configureMessageConverters(List> converters) { Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder = new Jackson2ObjectMapperBuilder(); converters.add(new MappingJackson2HttpMessageConverter(jackson2ObjectMapperBuilder.build())); Jaxb2RootElementHttpMessageConverter jaxb2RootElementHttpMessageConverter = new Jaxb2RootElementHttpMessageConverter(); converters.add(jaxb2RootElementHttpMessageConverter); } @Bean public ViewResolver viewResolver() { InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); viewResolver.setViewClass(JstlView.class); viewResolver.setPrefix("/WEB-INF/jsp/"); viewResolver.setSuffix(".jsp"); return viewResolver; } @Bean public static PropertySourcesPlaceholderConfigurer propertyConfig() { return new PropertySourcesPlaceholderConfigurer(); } }
Note the use of WebMvcConfigurerAdapter. It comes in handy when you want to work with Spring MVC. Especially note worthy is the configureMessageConverters() method. You would use that to configure a REST service. It would define how Spring handles the @ResponseBody or @RestController annotation, to translate a POJO to the response type: json, xml, etc. In the above example, we are using MappingJackson2HttpMessageConverter to convert our POJOs to JSON and Jaxb2RootElementHttpMessageConverter to convert them to XML.
import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class BankDetail { private int id; private int age; private String job; private String marital; private String education; private String defaulted; private BigDecimal balance; private String housing; private String loan; private String contact; private int day; private String month; private int duration; private int campaign; private int pdays; private int previous; private String poutcome; private String y; .... }
Note the use of @XmlRootElement. This is absolutely necessary as we are using Jaxb2RootElementHttpMessageConverter to convert our POJOs to xml. If you omit this, you will get a "Error 406 Not Acceptable" error, the underlying cause being:
org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation
@RestController public class SimpleBankDetailRestController { private final BankDetailService bankDetailService; @Autowired public SimpleBankDetailRestController(BankDetailService bankDetailService) { this.bankDetailService = bankDetailService; } @RequestMapping(path = { "/bank-detail" }, method = { RequestMethod.GET, RequestMethod.POST }) public BankDetail getBankDetail() { return bankDetailService.getBankDetails().get(0); } }
The controller is very simple, and returns the POJO. It is upto the HttpMessageConverter to make sense of it and convert that to either json or xml.
This makes the perfect sense, as the controller can just return the model, and the conversion can be a configuration detail.
Spring gives us the flexibility of doing away with the Accept header to specify the type of response. If we want json output, we can simply say:
http://localhost:8090/simple-spring-rest/bank-detail.json
For xml, we can similarly say:
http://localhost:8090/simple-spring-rest/bank-detail.xml
The sources can be found here:
https://github.com/paawak/blog/tree/master/code/simple-spring-rest