【问题标题】:How to serialize a json containing LAZY associations如何序列化包含 LAZY 关联的 json
【发布时间】:2018-12-08 17:21:27
【问题描述】:

我有一个Person 实体,它与Contact 实体有@ManyToOne 关联,获取类型为LAZY。我正在使用 spring-boot 来公开 REST API。我的一个 POST 调用包含嵌套 JSON 以保存父实体 Person 以及关联 Contact

由于Contact fetch type 是 LAZY,我遇到了以下异常

    ERROR 17415 --- [nio-8080-exec-4] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.example.rest.RestResultObject["results"]->java.util.ArrayList[0]->com.example.model.Person["contact"]->com.example.model.Contact_$$_jvst8d1_4["handler"])] with root cause

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.example.rest.RestResultObject["results"]->java.util.ArrayList[0]->com.example.model.Person["contact"]->com.example.model.Contact_$$_jvst8d1_4["handler"])
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77) ~[jackson-databind-2.9.3.jar:2.9.3]

无需将联系人更改为 EAGER。有没有最好的方法来解决这个问题?

更新:

Person.java

public class Person {
    private long id;
    private String name;
    private String rno;
    @ManyToOne(fetch = FetchType.LAZY)
    private Contact contact;

    // Getters and setters
}

Contact.java

public class Contact {
    private long id;
    private String info;
    @OneToMany
    private List<Person> persons;
}

【问题讨论】:

  • 能否请您添加人员和联系人的代码?
  • @MarufHassan 更新了我的帖子

标签: java spring-boot jpa serialization jackson


【解决方案1】:

我添加了以下内容

  • 每个对象上的@Entity
  • 将 id 中的 long 更改为 Long,如果您使用 Spring Data JPA,这将对您有所帮助
  • 添加@Id将id声明为主键
  • @JsonBackReference & @JsonManagedReference 避免杰克逊的无限循环

人物类

@Entity
public class Person {

 @Id
 @GeneratedValue(strategy = GenerationType.IDENTITY)
 private Long id;

 private String name;

 private String rno;

 @JsonManagedReference
 @ManyToOne(fetch = FetchType.LAZY)
 private Contact contact;

 //setter & getter

}

联系班级

@Entity
public class Contact {

 @Id
 @GeneratedValue(strategy = GenerationType.IDENTITY)
 private Long id;

 private String info;

 @JsonBackReference
 @OneToMany(cascade = CascadeType.ALL, mappedBy = "contact")
 private List<Person> persons;

 //setter & getter
}

并添加依赖项

<dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-hibernate5</artifactId>
</dependency>

最后添加一个新配置

@Configuration
public class JacksonConfig {

@Bean
public Jackson2ObjectMapperBuilderCustomizer addCustomBigDecimalDeserialization() {
    return new Jackson2ObjectMapperBuilderCustomizer() {
        @Override
        public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {
            jacksonObjectMapperBuilder.featuresToDisable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
            jacksonObjectMapperBuilder.modules(new Hibernate5Module());
        }

    };
}
}

【讨论】:

  • 使用此解决方案,我们无法获取关联实体的数据。你知道我们怎样才能得到它吗?
  • @OneToMany 默认是惰性的。在这个注解上使用 fetch 类型。
  • 谢谢,但在我的情况下它不起作用。你想看看这里的代码吗:github.com/JavaHelper/issue-jackson-boot
  • 另外,我发现 Swagger-fox 效果不好,给RangeError: Maximum call stack size exceeded
  • 另外,这种方法的日期类似于“createdDate”:{“epochSecond”:1565115275,“nano”:767000000},“lastUpdateDate”:{“epochSecond”:1565115275,“nano”: 767000000 },
【解决方案2】:

问题很可能与事务处理有关。 JSON 序列化在事务范围之外执行。如果是这样,最简单的解决方案(从架构的角度来看不一定是最好的)是创建包装实体加载的服务(专用于 REST 操作)并执行相关数据的“延迟化”,例如(关键元素是@Transactional注解)。

@Sevice
@Transactional(readOnly=true)
public class DataReaderServiceImpl extends DataLoaderService{
    //initialization code
    public Person loadPerson(PredicatesType somePredicate){
        Person person = //get person using predicates expression
        //"delazy" contacts in transaction scope
        person.getContacts();
        return person;
    }
}

从架构上讲,在这样的服务中,最好映射到 DTO 并返回 DTO 实例而不是实体。

【讨论】:

    【解决方案3】:

    这是通过使用@JsonIgnore 注释以及fethType.LAZY

    来解决问题的一种方法
    public class Person {
        private long id;
        private String name;
        private String rno;
        @ManyToOne(fetch = FetchType.LAZY)
        @JsonIgnore
        private Contact contact;
    
        // Getters and setters
    }
    
    public class Contact {
        private long id;
        private String info;
        @OneToMany
        private List<Person> persons;
    }
    

    【讨论】:

      猜你喜欢
      • 2019-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-14
      • 2016-04-22
      • 1970-01-01
      相关资源
      最近更新 更多