如何序列化包含LAZY关联的JSON
如何序列化包含LAZY关联的JSON
我有一个实体类\"Person\",它与\"Contact\"实体类有一个\"ManyToOne\"的关联关系,关联方式为\"LAZY\"。我使用spring-boot暴露REST API。我的POST请求中包含嵌套的JSON,用于保存父实体\"Person\"以及关联的\"Contact\"。\n由于\"Contact\"的关联方式是\"LAZY\",我遇到了以下异常:\n\"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\ncom.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\"])\nat com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77) ~[jackson-databind-2.9.3.jar:2.9.3]\"\n在不将\"Contact\"更改为\"EAGER\"的情况下,有没有更好的解决方法?\n更新内容:\nPerson.java\n
public class Person { private long id; private String name; private String rno; @ManyToOne(fetch = FetchType.LAZY) private Contact contact; // Getters and setters }
\nContact.java\n
public class Contact { private long id; private String info; @OneToMany private Listpersons; }
一、问题的原因:
问题的出现是因为在序列化一个包含延迟加载(LAZY)关联的JSON时,关联对象(Contact)的属性不会被立即加载,导致在序列化时无法获取到关联对象的数据。
二、解决方法:
为了解决这个问题,可以使用注解@JsonIgnore
和fetch = FetchType.LAZY
。
具体的解决方法如下:
1. 在Person
类中,将关联对象Contact
的加载方式设置为fetch = FetchType.LAZY
,即延迟加载。
public class Person { private long id; private String name; private String rno; (fetch = FetchType.LAZY) private Contact contact; // Getters and setters }
2. 在Contact
类中,使用@JsonIgnore
注解来忽略关联对象persons
的序列化。
public class Contact { private long id; private String info; @JsonIgnore private List<Person> persons; }
通过以上两步的操作,即可解决序列化包含延迟加载关联的JSON时的问题。
这样,当序列化一个包含延迟加载关联的JSON时,关联对象的属性不会被立即加载,从而避免了在序列化时无法获取到关联对象的数据的问题。
问题的出现主要与事务处理有关。JSON序列化是在事务范围之外执行的。如果是这样,最简单的解决方案(从架构角度来看并不一定是最好的)是创建一个服务来包装实体加载(专门用于REST操作),并执行相关数据的“去懒加载”操作,例如(关键元素是注释)。
(readOnly=true) public class DataReaderServiceImpl extends DataLoaderService{ //初始化代码 public Person loadPerson(PredicatesType somePredicate){ Person person = //使用谓词表达式获取人员 //"去懒加载"事务范围内的联系人 person.getContacts(); return person; } }
从架构上讲,在这样的服务中,最好将实体映射到DTO,并返回DTO实例而不是实体。
在这个问题中,出现的原因是JSON序列化包含LAZY关联的对象时无法获取关联实体的数据。为了解决这个问题,下面是一些解决方法:
首先,在每个对象上添加以下内容:
- 在id中将long改为Long,这将有助于使用Spring Data JPA。
- 添加@GeneratedValue(strategy = GenerationType.IDENTITY)来声明id为主键。
- 添加@JsonManagedReference和@JsonBackReference来避免Jackson的无限循环。
Person类:
public class Person { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private String rno; @ManyToOne(fetch = FetchType.LAZY) @JsonBackReference private Contact contact; //setter & getter }
Contact类:
public class Contact { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String info; @OneToMany(cascade = CascadeType.ALL, mappedBy = "contact") @JsonManagedReference private Listpersons; //setter & getter }
然后,添加以下依赖项:
com.fasterxml.jackson.datatype jackson-datatype-hibernate5
最后,添加一个新的配置类:
public class JacksonConfig { public Jackson2ObjectMapperBuilderCustomizer addCustomBigDecimalDeserialization() { return new Jackson2ObjectMapperBuilderCustomizer() { public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) { jacksonObjectMapperBuilder.featuresToDisable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); jacksonObjectMapperBuilder.modules(new Hibernate5Module()); } }; } }
通过这个解决方案,我们可以获取关联实体的数据。但是有一个问题是,日期的格式不正确。可以通过将日期格式化为所需的格式来解决这个问题。
通过在实体类上添加相应的注解,并添加适当的依赖项和配置,我们可以解决JSON序列化包含LAZY关联的对象的问题。