当子元素(即孙子集合)的成员集合延迟初始化时,我在 Jackson FasterXML 序列化为 JSON 时遇到问题。
以下是实体外观的示例:
@Entity
public class Parent {
@ManyToMany(fetch = FetchType.LAZY)
@JsonManagedReference
private List<Child> children;
}
@Entity
public class Child {
@ManyToMany(fetch = FectchType.LAZY)
@JsonBackReference
private List<Parent> parent;
@OneToMany(fetch = FectchType.LAZY)
@JsonManagedReference
private List<Grandchild> grandChildren;
}
应用程序比较大,实体较多,实体之间关系较多。如果我急切地加载所有内容或使用属性
spring.jpa.open-in-view=true
,那将会非常慢。相反,所需实体的子级会在数据库事务中加载,而其他所有内容都是延迟初始化的。
序列化时抛出的异常如下:
com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: domain.Child.grandchildren, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->domain.Parent["children"]->org.hibernate.collection.internal.PersistentBag[0]->domain.Child["grandChildren"])
当然,考虑到这一点,杰克逊需要序列化那些延迟初始化的属性和它发现为空的成员集合 - 但我还没有弄清楚如何做到这一点。
我做了研究,发现有一个模块可以帮助解决这个问题:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-hibernate5</artifactId>
</dependency>
所以我按如下方式配置了 Jackson - 但例外仍然存在。
@Configuration
public class JacksonConfig {
@Bean
public MappingJackson2HttpMessageConverter configureObjectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
Hibernate5Module hibernate5Module = new Hibernate5Module();
hibernate5Module.configure(Hibernate5Module.Feature.FORCE_LAZY_LOADING, false);
hibernate5Module.configure(Hibernate5Module.Feature.USE_TRANSIENT_ANNOTATION, false);
hibernate5Module.configure(Hibernate5Module.Feature.REQUIRE_EXPLICIT_LAZY_LOADING_MARKER, false);
hibernate5Module.configure(Hibernate5Module.Feature.WRITE_MISSING_ENTITIES_AS_NULL, true);
objectMapper.registerModule(hibernate5Module);
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(objectMapper);
return converter;
}
}
我被困住了!我不知道为什么我提供的配置不起作用。
依赖信息:
2.6.6
5.6.7.Final
2.13.2
2.13.2
忽略惰性获取字段的自定义过滤器
自定义过滤器
import jakarta.persistence.Persistence;
public class LazyFieldsFilter {
@Override
public boolean equals(Object obj) {
return !Persistence.getPersistenceUtil().isLoaded(obj);
}
}
使用过滤器
@Entity
@Table(name = CUSTOMER_DB_TABLES.CUSTOMER_ORDER_PRODUCTS)
@Setter
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class OrderProduct {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@JsonInclude(value = JsonInclude.Include.CUSTOM, valueFilter = LazyFieldsFilter.class)
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "product_method_id")
private ShippingMethod shippingMethod;
}
信用:JavaChina