当jackson序列化json对象时如何防止hibernate5延迟获取?

Posted

技术标签:

【中文标题】当jackson序列化json对象时如何防止hibernate5延迟获取?【英文标题】:How to prevent hibernate5 from lazy fetching when jackson serializes json object? 【发布时间】:2018-01-26 09:42:11 【问题描述】:

我目前正在运行一个 spring-boot 应用程序,其中端点返回存储在数据库中的特定对象的页面。出于我们的目的,我们称该对象为“x”。在“x”中有一个设置为延迟获取的对象列表。

@Entity
@DynamicUpdate
class x 

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

      @JsonIgnore
      @OneToMany(mappedBy = "x", cascade = CascadeType.MERGE, fetch = FetchType.LAZY)
      private List<y> lazilyFetchedList;

      @Override
      public Integer getId() 
           return id;
      

      public void setId(Integer id) 
           this.id = id;
      

      @JsonIgnore
      public List<y> getLazilyFetchedList() 
           return lazilyFetchedList;
      

      public void setLazilyFetchedList(List<y> lazilyFetchedList) 
           this.lazilyFetchedList = lazilyFetchedList;
      

我在上面设置了@JsonIgnore,因为我不希望在 GET 调用时将lazilyFetchedList 发送给客户端。

我的问题是,即使作为查看 JSON 响应的客户端,jackson 成功忽略了该字段。但是,当序列化 Java 对象“x”时,hibernate 仍然会进行额外的查询来获取 lazilyFetchedList(即使 jackson 没有使用结果)。

我已经尝试了Avoid Jackson serialization on non fetched lazy objects 的答案,但似乎没有一个答案有效。

这是我的控制器的样子:

    @RequestMapping(value = "/id/x", method = RequestMethod.GET)
    public ApiResponse<?> findX(@PathVariable Integer id, PagingInfo info) 
        Page<x> page = repo.findX(id, toPageable(info));
        return toResponse(page, FIND_LIST_STATUS);
     

这是我对对象映射器的配置:

@Configuration
@EnableWebMvc
public class ApiWebConfig extends WebMvcConfigurerAdapter 

@Bean
public ObjectMapper objectMapper() 
    ObjectMapper objectMapper = new ObjectMapper();
    configureDefaultObjectMapper(objectMapper);
    customizeObjectMapper(objectMapper);
    return objectMapper;


public static void configureDefaultObjectMapper(ObjectMapper objectMapper) 
    objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
    objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);
    objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
    objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);

    objectMapper.registerModule(new Hibernate5Module());

    JavaTimeModule javaTimeModule = new JavaTimeModule();
    javaTimeModule.addSerializer(ZonedDateTime.class, ZonedDateTimeSerializer.INSTANCE);
    javaTimeModule.addSerializer(OffsetDateTime.class, OffsetDateTimeSerializer.INSTANCE);
    objectMapper.registerModule(javaTimeModule);


/**
 * Only register a json message converter
 */
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) 
    converters.clear();

    MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
    converter.setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_JSON, ActuatorMediaTypes.APPLICATION_ACTUATOR_V1_JSON));
    converter.setObjectMapper(objectMapper());

    converters.add(converter);


版本:

Spring-Boot 1.5.3 杰克逊 2.8.6 休眠 5.0.11.Final jackson-datatype-hibernate5 2.9.0

【问题讨论】:

如果删除 getter/setter 会发生什么? 不要使用实体类,而是为 json 创建 pojo.. 问题是,我的项目中有很多实体。因此,为每个人创建一个 pojo 将不是一个可行的解决方案,而且我不想实现一个需要在两个不同位置更改字段的解决方案,因为如果有人要更新该实体,代码很可能会中断。我想要一个由图书馆自己处理的更通用的解决方案。 【参考方案1】:

将以下依赖项添加到您的 pom.xml:

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

(如果不是spring-boot-dependencies或者spring-boot-starter-parent管理的版本,添加) 将以下代码添加到您的 spring 配置类中:

@Bean
protected Module module() 
    return new Hibernate5Module();

使用以下导入:

import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module;

【讨论】:

以上是关于当jackson序列化json对象时如何防止hibernate5延迟获取?的主要内容,如果未能解决你的问题,请参考以下文章

如何让Jackson JSON生成的数据包含的中文以unicode方式编码

如何根据json中的属性编写jackson反序列化器

Scala:如何使用null来防止Jackson反序列化

如何使用 Jackson 反序列化来自 json 对象的对象数组

如何使用jackson(Java)反序列化对象中的json对象?

Jackson序列化(8)— 支持泛型的反序列化