Null id property on json deserialization with jackson and Jackson2HalModule Spring Hateoas

My essence:

public class User { private Integer id; private String mail; private boolean enabled; // getters and setters } 

Test.json file (response from REST web service):

 { "_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 do not understand, because the id property in the user is the only missing one (the mail and enabled properties are not empty) ...

What do I need to do to fix this? Is this a bug in Jackson or Spring Jackson2HalModule?

You can reproduce the cloning of my spring-hateoas fork repository and running unit tests.

+6
source share
4 answers

Actually, this was due to the Resource class, which is built to transfer the contents of your bean. The content property is annotated by @JsonUnwrapped , so the Resource class can display your bean in this property, while in json the bean properties are at the same level as the _links property. Using this annotation, it is possible that the property name conflicts with the wrapper and internal bean. This is just because the 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 problem. You can create a new MixIn class, inherited from the ResourceSupportMixin class, and override the getId() method with the @JsonIgnore(false) annotation:

 public abstract class IdResourceSupportMixin extends ResourceSupportMixin { @Override @JsonIgnore(false) public abstract Link getId(); } 

Then you just need to add your IdResourceSupportMixin class to your ObjectMapper :

 mapper.addMixInAnnotations(ResourceSupport.class, IdResourceSupportMixin.class); 

He must solve the problem.

+10
source

This worked for me:

 public class User extends ResourceSupport { @JsonIgnore(false) private Integer id; private String mail; private boolean enabled; // getters and setters } 

Also, modify your http client to return PagedResources <User> instead of PagedResources<Resource<User>>

0
source

With this code, you will find all @Entity beans to change the configuration to display the Id value:

  import java.util.LinkedList; import java.util.List; import javax.persistence.Entity; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; import org.springframework.core.type.filter.AnnotationTypeFilter; import org.springframework.data.rest.core.config.RepositoryRestConfiguration; import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter; import org.springframework.stereotype.Component; import com.rvillalba.exampleApiHateoas.entity.Example; import lombok.extern.slf4j.Slf4j; @Component @Slf4j public class SpringDataRestCustomization extends RepositoryRestConfigurerAdapter { @Override public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) { listMatchingClasses(Entity.class).forEach(entity -> config.exposeIdsFor(entity)); } public List<Class> listMatchingClasses(Class annotationClass) { List<Class> classes = new LinkedList<Class>(); ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(true); scanner.addIncludeFilter(new AnnotationTypeFilter(annotationClass)); for (BeanDefinition bd : scanner.findCandidateComponents(Example.class.getPackage().getName())) { try { classes.add(Class.forName(bd.getBeanClassName())); } catch (ClassNotFoundException e) { log.error("listMatchingClasses problem", e); } } return classes; } } 
0
source

I faced the same problem rightly wrong. The failed mixin solution doesn't seem to work for me because I am getting a NullPointerException. The POJO extension also does not work, because the property types (Link in ResourceSupport and Long in my POJO) do not match.

Has anyone found another solution to solve it?

0
source

All Articles