In the last tutorial, we got familiar with creating a custom HTTPMessageConverter. In this tutorial, we will create another one. This HTTPMessageConverter will convert request body containing YAML content to user defined object and vice-versa. We are going to use SnakeYAML, which is a Java based processor for parsing YAML data to/from Java Objects.
Creating the Controller
@Controller
public class ExampleController {
@RequestMapping(
value = "/newEmployee",
consumes = "text/yaml",
produces = MediaType.TEXT_PLAIN_VALUE,
method = RequestMethod.POST)
@ResponseBody
@ResponseStatus(HttpStatus.OK)
public String handleRequest (@RequestBody Employee employee) {
System.out.printf("In handleRequest method, employee: %s%n", employee);
String s = String.format("Employee saved: " + employee.getName());
System.out.println(s);
return s;
}
@RequestMapping(
value = "/employee",
produces = "text/yaml",
method = RequestMethod.GET)
@ResponseBody
@ResponseStatus(HttpStatus.OK)
public Employee handleRequest2 (@RequestParam String id) {
//create a test employee
return new Employee(id, "Tina", "111-111-1111");
}
}
public class Employee {
private String id;
private String name;
private String phoneNumber;
.............
}
Creating the Converter
public class YamlHttpMessageConverter<T>
extends AbstractHttpMessageConverter<T> {
public YamlHttpMessageConverter () {
super(new MediaType("text", "yaml"));
}
@Override
protected boolean supports (Class<?> clazz) {
return true;
}
@Override
protected T readInternal (Class<? extends T> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
Yaml yaml = new Yaml();
T t = yaml.loadAs(inputMessage.getBody(), clazz);
return t;
}
@Override
protected void writeInternal (T t, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
Yaml yaml = new Yaml();
OutputStreamWriter writer = new OutputStreamWriter(outputMessage.getBody());
yaml.dump(t, writer);
writer.close();
}
}
Registering the Converter
@EnableWebMvc
@ComponentScan("com.logicbig.example")
public class AppConfig extends WebMvcConfigurerAdapter {
@Override
public void extendMessageConverters (List<HttpMessageConverter<?>> converters) {
converters.add(new YamlHttpMessageConverter<>());
}
}
Testing with JUnit tests
Testing request
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = AppConfig.class)
public class ControllerTest {
@Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
@Before
public void setup () {
DefaultMockMvcBuilder builder = MockMvcBuilders.webAppContextSetup(this.wac);
this.mockMvc = builder.build();
}
.............
@Test
public void testConsumerController () throws Exception {
MockHttpServletRequestBuilder builder =
MockMvcRequestBuilders.post("/newEmployee")
.contentType("text/yaml")
.accept(MediaType.TEXT_PLAIN_VALUE)
.content(getNewEmployeeInYaml());
this.mockMvc.perform(builder)
.andExpect(MockMvcResultMatchers.status()
.isOk())
.andExpect(MockMvcResultMatchers.content()
.string("Employee saved: Tina"))
.andDo(MockMvcResultHandlers.print());
;
}
.............
public String getNewEmployeeInYaml () {
return "id: 1\nname: Tina\nphoneNumber: 111-111-1111\n";
}
} Output In handleRequest method, employee: Employee{id='1', name='Tina', phoneNumber='111-111-1111'} Employee saved: Tina
MockHttpServletRequest: HTTP Method = POST Request URI = /newEmployee Parameters = {} Headers = {Content-Type=[text/yaml], Accept=[text/plain]}
Handler: Type = com.logicbig.example.ExampleController Method = public java.lang.String com.logicbig.example.ExampleController.handleRequest(com.logicbig.example.Employee)
Async: Async started = false Async result = null
Resolved Exception: Type = null
ModelAndView: View name = null View = null Model = null
FlashMap: Attributes = null
MockHttpServletResponse: Status = 200 Error message = null Headers = {Content-Type=[text/plain;charset=ISO-8859-1], Content-Length=[20]} Content type = text/plain;charset=ISO-8859-1 Body = Employee saved: Tina Forwarded URL = null Redirected URL = null Cookies = []
Testing response
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = AppConfig.class)
public class ControllerTest {
@Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
.............
@Test
public void testProducerController () throws Exception {
MockHttpServletRequestBuilder builder =
MockMvcRequestBuilders.get("/employee")
.accept("text/yaml")
.param("id", "1");
this.mockMvc.perform(builder)
.andExpect(MockMvcResultMatchers.status()
.isOk())
.andDo(MockMvcResultHandlers.print());
}
.............
} Output
MockHttpServletRequest: HTTP Method = GET Request URI = /employee Parameters = {id=[1]} Headers = {Accept=[text/yaml]}
Handler: Type = com.logicbig.example.ExampleController Method = public com.logicbig.example.Employee com.logicbig.example.ExampleController.handleRequest2(java.lang.String)
Async: Async started = false Async result = null
Resolved Exception: Type = null
ModelAndView: View name = null View = null Model = null
FlashMap: Attributes = null
MockHttpServletResponse: Status = 200 Error message = null Headers = {Content-Type=[text/yaml]} Content type = text/yaml Body = !!com.logicbig.example.Employee {id: '1', name: Tina, phoneNumber: 111-111-1111}
Forwarded URL = null Redirected URL = null Cookies = []
Example ProjectDependencies and Technologies Used: - spring-webmvc 4.3.8.RELEASE: Spring Web MVC.
- spring-test 4.3.8.RELEASE: Spring TestContext Framework.
- javax.servlet-api 3.0.1 Java Servlet API
- junit 4.12: JUnit is a unit testing framework for Java, created by Erich Gamma and Kent Beck.
- snakeyaml 1.18: YAML 1.1 parser and emitter for Java.
- JDK 1.8
- Maven 3.3.9
|