My entity :
public class User {
private Integer id;
private String mail;
private boolean enabled;
// getters and setters
}
File test.json (response from REST webservice) :
{
"_embedded" : {
"users" : [ {
"id" : 1,
"mail" : "admin@admin.com",
"enabled" : true,
"_links" : {
"self" : {
"href" : "http://localhost:8080/api/users/1"
}
}
} ]
}
}
And my test class :
public class TestJson {
private InputStream is;
private ObjectMapper mapper;
@Before
public void before() {
mapper = new ObjectMapper();
mapper.registerModule(new Jackson2HalModule());
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
is = TestJson.class.getResourceAsStream("/test.json");
}
@After
public void after() throws IOException {
is.close();
}
@Test
public void test() throws IOException {
PagedResources<Resource<User>> paged = mapper.readValue(is, new TypeReference<PagedResources<Resource<User>>>() {});
Assert.assertNotNull(paged.getContent().iterator().next().getContent().getId());
}
@Test
public void testResource() throws IOException {
PagedResources<User> paged = mapper.readValue(is, new TypeReference<PagedResources<User>>() {});
Assert.assertNotNull(paged.getContent().iterator().next().getId());
}
}
The second test passes but not the first. I don't understand because the id property in the user is the only one missing (mail and enabled properties are not empty)...
What do I have to do to fix it ? Is it a bug in Jackson or Spring Jackson2HalModule ?
You can reproduce by cloning my spring-hateoas fork repository and launching unit tests.
Actually, it was due to the Resource
class which is built to wrap the content of your bean. The content property is annotated by @JsonUnwrapped
so that the Resource
class can map your bean in this property whereas in the json, bean properties are at the same level as _links
property. With this annotation, it is possible to have property name conflict with the wrapper and the inner bean. It is exactly the case here because Resource
class has an id
property inherited from the ResourceSupport
class, and this property is sadly annotated by @JsonIgnore
.
There is a workaround for this issue. You can create a new MixIn
class inherited from the ResourceSupportMixin
class and override the getId()
method with @JsonIgnore(false)
annotation :
public abstract class IdResourceSupportMixin extends ResourceSupportMixin {
@Override
@JsonIgnore(false)
public abstract Link getId();
}
Then you just have to add your IdResourceSupportMixin
class to your ObjectMapper
:
mapper.addMixInAnnotations(ResourceSupport.class, IdResourceSupportMixin.class);
It should solve the problem.