In general a REST service serves JSON document formats. In Spring Boot it is even the standard without having to configure anything. Over HTTP we have the ability to send a Content-Type as header to instruct the server to return a certain document format (Mime type). Besides handling JSON, XML is another common document format. But what if we want to serve or read a YAML document format? This tutorial provides the required steps to be able to handle objects in YAML format. To be able to send a YAML Content-Type with the header, and to be able to serialize and deserialize with the existing ObjectMappers of Jackson. This tutorial will use Spring Boot, Jackson and a YAML dataformat extension library for Jackson.

Add dependency

First we need to add the YAML Jackson extension to our Gradle build file.

dependencies {
  compile 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.8.4'
}

Register ObjectMapper

Now we can create a specific ObjectMapper with a registered YAMLFactory. To create our YAML ObjectMapper the following line will:

@Configuration public class ObjectMapperConfiguration {

//This is our default JSON ObjectMapper. Add @Primary to inject is as default bean. @Bean @Primary public ObjectMapper objectMapper() { ObjectMapper objectMapper = new ObjectMapper(); //Enable or disable features return objectMapper; }

@Bean public ObjectMapper yamlObjectMapper() { ObjectMapper yamlObjectMapper = new ObjectMapper(new YAMLFactory()); //Enable or disable features return yamlObjectMapper; } }

Now we have registered two ObjectMapper instances. One for JSON and one for YAML. Both with the option to enable or disable features in the ObjectMapper.

Register MessageConverter and Content Negotiation

@Configuration
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {

  private static final MediaType MEDIA_TYPE_YAML = MediaType.valueOf("text/yaml");
  private static final MediaType MEDIA_TYPE_YML = MediaType.valueOf("text/yml");

  @Autowired
  @Qualifier("yamlObjectMapper")
  private ObjectMapper yamlObjectMapper;

  @Override
  public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
    configurer
      .favorPathExtension(true)
      .favorParameter(false)
      .ignoreAcceptHeader(false)
      .defaultContentType(MediaType.APPLICATION_JSON)
      .mediaType(MediaType.APPLICATION_JSON.getSubtype(),
                 MediaType.APPLICATION_JSON)
      .mediaType(MEDIA_TYPE_YML.getSubtype(), MEDIA_TYPE_YML)
      .mediaType(MEDIA_TYPE_YAML.getSubtype(), MEDIA_TYPE_YAML);
  }

  @Override
  public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
    MappingJackson2HttpMessageConverter yamlConverter =
        new MappingJackson2HttpMessageConverter(yamlObjectMapper);
    yamlConverter.setSupportedMediaTypes(
        Arrays.asList(MEDIA_TYPE_YML.getSubtype(), MEDIA_TYPE_YAML.getSubtype())
    );
    converters.add(yamlConverter);
  }
}

Read YAML file

Another option we have is to read YAML files and transform them into Objects. Lets say we already have a FileService that has functionality to read a file as an InputStream.

interface FileService {
  InputStream read(String name);
}

To transform this InputStream into an Object, we autowire the YAML ObjectMapper and provide the returned InputStream to the ObjectMapper.

@Service
public class CustomerService {
  @Autowired
  private FileService fileservice;

  @Autowired
  @Qualifier("yamlObjectMapper")
  private ObjectMapper yamlObjectMapper;

  public Customer get() {
    try {
      @Cleanup
      InputStream inputStream = fileservice.read("my-customer.yaml");
      return yamlObjectMapper.readValue(inputStream, Customer.class);
    } catch (IOException ex) {
      throw new IllegalStateException(ex);
    }
  }

  @Data
  public static class Customer {
    private String name;
    private String surname;
    private String email;
  }
}

NB. For this example Lombok was used http://projectlombok.org.

shadow-left