Java – Hal rendering cannot be obtained using spring HATEOAS and Jersey
I use spring initializr( https://start.spring.io/ )To create a starter application with only "Jersey (Jax - RS)" and "HATEOAS"
My goal is:
{ "name": "Hello","count": 42,"_links": { "self": { "href": "http://localhost:8080/api/foo" } } }
What I have now is:
{ "name": "Hello","links": [ { "rel": "self","href": "http://localhost:8080/api/foo" } ] }
In addition to the class generated by initializr, I added this configuration
@Configuration @ApplicationPath("api") @Component @EnableHypermediaSupport(type = HAL) public class JerseyConfig extends ResourceConfig { public JerseyConfig() { registerEndpoints(); } private void registerEndpoints() { register(FooResource.class); } }
This resource (endpoint):
@Component @Path("foo") public class FooResource { @GET @Produces(MediaTypes.HAL_JSON_VALUE) public Resource<Foo> getFoo() { final Resource<Foo> fooTo = new Resource<>(new Foo("Hello",42)); fooTo.add(JaxRsLinkBuilder.linkTo(FooResource.class).withRel("self")); return fooTo; } }
And a virtual bean:
public class Foo { private String name; private int count; public Foo() { } public Foo(String name,int count) { this.name = name; this.count = count; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getCount() { return count; } public void setCount(int count) { this.count = count; } }
I also tried to add
@EnableHypermediaSupport(type = HAL)
Next to @ springbootapplication in the application class
When I
GET localhost:8080/api/foo
I received a reply with the correct content type
application/hal+json;charset=UTF-8
But it is still in the wrong format ("link" attribute as array, installed "_links" attribute as object / map)
Solution
Just to add @ zerflagl's answer, to register jackson2halmodule, you should use a contextresolver, as described here In addition, at the top of this module, you need to use objectmapper to configure halhandlerinstantiator If you miss the last part, you will get an exception that Jackson cannot instantiate the serializer because there is no default constructor
@Provider public class JacksonContextResolver implements ContextResolver<ObjectMapper> { private final ObjectMapper mapper = new ObjectMapper(); public JacksonContextResolver() { mapper.registerModule(new Jackson2HalModule()); mapper.setHandlerInstantiator(new HalHandlerInstantiator( new AnnotationRelProvider(),null,null)); } @Override public ObjectMapper getContext(Class<?> type) { return mapper; } }
Then simply register the context parser with Jersey resourceconfig
register(new JacksonContextResolver());