Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to enable HAL rendering without using @EnableHypermediaSupport with spring hateoas?

With @EnableHypermediaSupport(type = HypermediaType.HAL) Spring hateoas provides a simple and convenient way to enable HAL rendering.

The annotations triggers some configuration magic which is explained here: https://github.com/spring-projects/spring-hateoas#enablehypermediasupport

However if you are working on a given xml-config based spring application, it is not easy to integrate @EnableHypermediaSupport. I tried a lot of different ways to enable HAL rendering but no single solution was working correctly:

  • Including a configuration class in existing mvc servlet xml configuration.
  • Using different versions of spring hateos (0.70.0, 0.80.0, 0.9.0.BUILD-SNAPSHOT), hoping that 0.90.0 will produce HAL out of the box, since, according to a jira issue, it should become the default rendering (at least for spring data rest).
  • Using a custom MappingJackson2HttpMessageConverter to register a new Jackson2HalModule() also did not work. Although the converter was used for rendering (for example to render Dates), the output was not rendered in HAL.

Therefore my question: How can I enable HAL rendering without using EnableHypermediaSupport?

I intentionally left out any code snippets, because I don't think that it would help much.

like image 543
user3180909 Avatar asked Jan 10 '14 09:01

user3180909


People also ask

What is Hal HATEOAS?

HAL is a simple format that gives a consistent and easy way to hyperlink between resources in your API. The HAL format is strictly coupled to HATEOAS. The main target of HATEOAS is to decouple the API Consumer from the paths used in the API.

Why do we need spring HATEOAS?

Spring HATEOAS provides some APIs to ease creating REST representations that follow the HATEOAS principle when working with Spring and especially Spring MVC. The core problem it tries to address is link creation and representation assembly.

What is _embedded in JSON?

resources. "_embedded": contains embedded resources. All other properties MUST be valid JSON, and represent the current state of the resource. The reserved "_links" property.


2 Answers

Based on @WaldemarSchneider answer, here is a concrete how-to:

Create an HTTP message converter:

public class HalHttpMessageConverter extends AbstractJackson2HttpMessageConverter {

  public HalHttpMessageConverter() {
    super(new ObjectMapper(), new MediaType("application", "hal+json", DEFAULT_CHARSET));
    objectMapper.registerModule(new Jackson2HalModule());
    objectMapper.setHandlerInstantiator(new Jackson2HalModule.HalHandlerInstantiator(new DefaultRelProvider(), null));
    // customize your mapper if needed
    objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
  }

  @Override
  protected boolean supports(Class<?> clazz) {
    return ResourceSupport.class.isAssignableFrom(clazz);
  }

}

Register it in your servlet context:

<mvc:annotation-driven>
  <mvc:message-converters>
    <bean class="package.to.HalHttpMessageConverter" />
  </mvc:message-converters>
</mvc:annotation-driven>

And don't forget to make your rest controllers produce application/hal+json:

@RestController
@RequestMapping(value = "/articles", produces = "application/hal+json")
public class ArticleRestController {
  ...
}
like image 109
sp00m Avatar answered Nov 11 '22 05:11

sp00m


Maybe this question is a little bit old but i want to provide my solution for the following users.

I had similiar circumstances (Spring MVC 3.2.10.RELEASE, Spring HATEAOS 0.16.0.RELEASE) to configure spring hateoas to use hypermedia without java configuration.

My solution was the following:

Create a custom HalJacksonHttpMessageConverter (which acts similiar as the Spring MVC standard MappingJacksonHttpMessageConverter, it also have to have a method which exposes the ObjectMapper) but register application/hal+json as the supported hypermediatypes. The supports method should return true if the given class is assignable from ResourceSupport.

Create a RelProvider (the DefaultRelProvider fulfilled my needs in this case) in your xml configuration.

I created a BeanPostProcessorBean (implemented interfaces: BeanPostProcessor and BeanFactoryAware). Enrich the existing ObjectMapper from my HalJachsonHttpMessageConverter with the following settings:

// retrieve the object mapper from the messageConverter
RelProvider provider = beanFactory.getBean("relProvider", RelProvider.class);
ObjectMapper mapper = (ObjectMapper) objectMapper;
mapper.registerModule(new Jackson2HalModule());
mapper.setHandlerInstantiator(new Jackson2HalModule.HalHandlerInstantiator(provider, null));
mapper.enable(SerializationFeature.INDENT_OUTPUT);

Register these beans in your spring bean xml. I hope this helps. If someone has a better configuration approach, please let me know.

like image 2
Waldemar Schneider Avatar answered Nov 11 '22 05:11

Waldemar Schneider