在做的项目采用的是spring jpa,底层默认使用的是orm是hibernate,通过hibernate查询出来的实体对象实际上都是代理对象,在序列化的时候,我们可能会遇到懒加载导致jackson无法正确解析对象的问题,这个可以通过导入maven包
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-hibernate5</artifactId>
</dependency>
然后加载进objectMapper上下文
@Bean
public Jackson2ObjectMapperBuilderCustomizer builderCustomizer() {
return builder -> {
//jackson序列化 和 hibernate懒加载
builder.modulesToInstall(hibernate5Module());
};
}
private static Hibernate5Module hibernate5Module() {
Hibernate5Module hibernate5Module = new Hibernate5Module();
hibernate5Module.configure(REPLACE_PERSISTENT_COLLECTIONS, true);
//hibernate5Module.configure(FORCE_LAZY_LOADING, true);
return hibernate5Module;
}
这样在序列化的时候就会判断之前是否存在数据了,如果是懒加载则会序列化为null。
我在反序列化的时候会报failed to lazily initialize a collection, could not initialize proxy...,后来看了一下序列化后的json,发现有些延迟加载的Collection类型的会解析成org.hibernate.collection.internal.PersistentBag(hibernate的代理对象),而不是咱们一般json的集合形式。导致反序列化的时候,会生成PersistentBag对象,这时候jackson操作PersistentBag,会导致hibernate检测到数据变动,从而触发它的一些操作而报上面的错。
然后我就排查,为啥序列化的时候会转成PersistentBag对象呢?可以看看Hibernate5Module里的代码,该模块会加载两个
context.addSerializers(new HibernateSerializers(_mapping, _moduleFeatures));
context.addBeanSerializerModifier(new HibernateSerializerModifier(_moduleFeatures, _sessionFactory));
//序列化处理器,咱们之前的处理懒加载原理也是通过这两个处理的,然后我在
HibernateSerializerModifier里看到了PersistentCollectionSerializer,对于集合类型的解析处理,其中主要有个判断方法
protected boolean usesLazyLoading(BeanProperty property) {
if (property != null) {
// As per [Issue#36]
ElementCollection ec = property.getAnnotation(ElementCollection.class);
if (ec != null) {
return (ec.fetch() == FetchType.LAZY);
}
OneToMany ann1 = property.getAnnotation(OneToMany.class);
if (ann1 != null) {
return (ann1.fetch() == FetchType.LAZY);
}
OneToOne ann2 = property.getAnnotation(OneToOne.class);
if (ann2 != null) {
return (ann2.fetch() == FetchType.LAZY);
}
ManyToOne ann3 = property.getAnnotation(ManyToOne.class);
if (ann3 != null) {
return (ann3.fetch() == FetchType.LAZY);
}
ManyToMany ann4 = property.getAnnotation(ManyToMany.class);
if (ann4 != null) {
return (ann4.fetch() == FetchType.LAZY);
}
// As per [Issue#53]
return !Feature.REQUIRE_EXPLICIT_LAZY_LOADING_MARKER.enabledIn(_features);
}
return false;
}
发现我关联字段上使用的是@ManyToMany(fetch = FetchType.EAGER),因为我之前为了处理懒加载就加上的,现在可以去掉了,问题也得到了解决。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。