javaspring-bootjacksonyaml

Spring Boot - RestController Deserializing YAML Uploads?


How can I configure a Spring Boot RestController to accept YAML uploads?

The following results in a 415. I can see from debugging that the MappingJackson2HttpMessageConverter instances in my Spring context only support [application/json;charset=UTF-8, application/*+json;charset=UTF-8]. I can't be the only Spring Boot user trying to do this, and I'm surprised it doesn't just work - most things do in Spring Boot!

I've got the YAML dataformat in my POM:

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

My RestController has a method thus:

@RequestMapping(method=RequestMethod.POST, value="/", consumes="application/yaml")
public String upload(@RequestBody Declaration declaration) {
    //Do stuff
}

And my test:

@Test
public void triggersConvergence() throws Exception {
    ClassPathResource fixture = new ClassPathResource("declaration.yml");
    HttpHeaders requestHeaders = new HttpHeaders();
    requestHeaders.add("Content-Type", "application/yaml");
    requestHeaders.add("Accept", "application/json");

    URI uri = new URI("http://127.0.0.1:"+port);
    byte[] bytes = new byte[(int)fixture.contentLength()];
    fixture.getInputStream().read(bytes);
    RequestEntity<byte[]> postRequest = new RequestEntity<byte[]>(bytes, requestHeaders, HttpMethod.POST, uri);

    ResponseEntity<String> response = rest.exchange(postRequest, String.class);
    assertThat(response.getStatusCode(), is(HttpStatus.OK));
    assertThat(response.getBody(), is("Converged org my-lovely-org"));
}

Solution

  • While this functionality is not available in Spring it's easy to add using YAMLMapper it in 2 simple steps:

    1. Define your own HttpMessageConverter that supports Content-Type: application/yaml:

       final class YamlJackson2HttpMessageConverter extends AbstractJackson2HttpMessageConverter {
           YamlJackson2HttpMessageConverter() {
               super(new YAMLMapper(),
                       MediaType.parseMediaType("application/yaml"),
                       MediaType.parseMediaType("application/*+yaml"));
           }
       }
      
    2. Register your converter:

       @Configuration
       public class YamlConfiguration extends WebMvcConfigurerAdapter {
           @Override
           public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
               converters.add(new YamlJackson2HttpMessageConverter());
           }
       }
      

    Enjoy controller methods consuming and producing application/yaml from POJOs.