【问题标题】:Null id property when deserialize json with jackson and Jackson2HalModule of Spring Hateoas使用 Spring Hateoas 的 jackson 和 Jackson2HalModule 反序列化 json 时的空 id 属性
【发布时间】:2015-08-22 02:17:16
【问题描述】:

我的实体:

public class User {

    private Integer id;
    private String mail;
    private boolean enabled;

    // getters and setters
}

文件 test.json(来自 REST 网络服务的响应):

{
 "_embedded" : {
  "users" : [ {
    "id" : 1,
    "mail" : "admin@admin.com",
    "enabled" : true,
    "_links" : {
      "self" : {
        "href" : "http://localhost:8080/api/users/1"
      }
    }
  } ]
 }
}

还有我的测试课:

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());
    }
}

第二个测试通过但第一个没有通过。我不明白,因为 user 中的 id 属性是唯一缺少的(mail 和 enabled 属性不为空)...

我该怎么做才能修复它?这是 Jackson 或 Spring Jackson2HalModule 中的错误吗?

您可以通过克隆我的 spring-hateoas fork repository 并启动单元测试来重现。

【问题讨论】:

    标签: java jackson spring-data-rest spring-hateoas hal


    【解决方案1】:

    实际上,这是因为 Resource 类是为了包装 bean 的内容而构建的。 content 属性由@JsonUnwrapped 注释,以便Resource 类可以在此属性中映射您的bean,而在json 中,bean 属性与_links 属性处于同一级别。使用此注解,可能会与包装器和内部 bean 发生属性名称冲突。这里正是如此,因为Resource 类有一个从ResourceSupport 类继承的id 属性,而这个属性不幸被@JsonIgnore 注释。

    有解决此问题的方法。您可以创建一个新的MixIn 类继承自ResourceSupportMixin 类,并使用@JsonIgnore(false) 注释覆盖getId() 方法:

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

    然后您只需将您的 IdResourceSupportMixin 类添加到您的 ObjectMapper

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

    应该能解决问题。

    【讨论】:

    • spring-hateoasspring-boot 存在同样的问题,所以我不得不将 id 重命名为其他名称
    • 那是一年前的事,但如果我没记错的话,它实际上不起作用,因为我认为编译错误......我找到的唯一一个解决方案是 cahen 的解决方案。您必须将您的 id 属性重命名为其他名称。
    • 这对我有用:objectMapper.addMixIn(Resource.class, IdResourceSupportMixIn.class); - 使用 jackson 2.8.8 和 spring-hateoas 0.28,以及其余模板。但它打破了response.getBody().getId()
    • ResourceSupportMixin 是包私有的。我们不能扩展它。但我找到了解决方案。用这个。 ``` 公共抽象类 IdResourceSupportMixin 扩展 ResourceSupport { @Override @JsonIgnore(false) 公共抽象链接 getId(); @Override @XmlElement(name = "link") @JsonProperty("_links") @JsonInclude(JsonInclude.Include.NON_EMPTY) @JsonSerialize(using = Jackson2HalModule.HalLinkListSerializer.class) @JsonDeserialize(using = Jackson2HalModule.HalLinkListDeserializer.class) public抽象列表 getLinks(); } ```
    【解决方案2】:

    使用此代码,您可以找到所有 @Entity bean 并更改配置以公开 Id 值:

     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;
         }
    
     }
    

    【讨论】:

    • 这个解决方案对我有用。谢谢@Raul Villalba。我用我的BaseEntity 替换了Example 类,我在其中定义了private Long id,它起作用了。我还将课程更改为public class SpringDataRestCustomization implements RepositoryRestConfigurer,因为RepositoryRestConfigurerAdapter 已被弃用。 docs.spring.io/spring-data/rest/docs/3.3.1.RELEASE/api/org/…
    【解决方案3】:

    这对我有用:

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

    另外,将您的 http 客户端更改为返回 PagedResources &lt;User&gt; 而不是 PagedResources&lt;Resource&lt;User&gt;&gt;

    【讨论】:

    • 如果 ResourceSupport 有 public Link getId() 方法,你是如何获得 Integer id 字段的?
    • @MikhailKopylov 你是对的。 @Will Franco - 这个解决方案不起作用。这是我看到的错误。 'getId()' in 'com.example.entity.User' clashes with 'getId()' in 'org.springframework.hateoas.ResourceSupport'; attempting to use incompatible return type
    猜你喜欢
    • 1970-01-01
    • 2016-10-15
    • 2013-04-09
    • 2020-07-09
    • 1970-01-01
    • 1970-01-01
    • 2012-08-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多