避免对未获取的惰性对象进行 Jackson 序列化

2022-08-31 11:08:14

我有一个返回User对象的简单控制器,这个用户有一个具有休眠属性FetchType.LAZY的属性坐标。

当我尝试获取此用户时,我总是必须加载所有坐标才能获取用户对象,否则当 Jackson 尝试序列化 User 时,将引发异常:

com.fasterxml.jackson.databind.JsonMappingException: 無法初始化 proxy - no Session

这是由于杰克逊试图获取这个未提取的对象。以下是对象:

public class User{

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
    @JsonManagedReference("user-coordinate")
    private List<Coordinate> coordinates;
}

public class Coordinate {

    @ManyToOne
    @JoinColumn(name = "user_id", nullable = false)
    @JsonBackReference("user-coordinate")
    private User user;
}

控制器:

@RequestMapping(value = "/user/{username}", method=RequestMethod.GET)
public @ResponseBody User getUser(@PathVariable String username) {

    User user = userService.getUser(username);

    return user;

}

有一种方法可以告诉 Jackson 不要序列化未提取的对象?我一直在寻找3年前实现jackson-hibernate-module的其他答案。但也许可以通过新的杰克逊功能来实现。

我的版本是:

  • 弹簧 3.2.5
  • 休眠 4.1.7
  • 杰克逊 2.2

提前致谢。


答案 1

我终于找到了解决方案!感谢indybee给了我一个线索。

教程Spring 3.1,Hibernate 4和Jackson-Module-Hibernate为Spring 3.1及更早版本提供了很好的解决方案。但是由于版本3.1.2 Spring拥有自己的PingJackson2HttpMessageConverter,其功能与本教程中的功能几乎相同,因此我们不需要创建自定义HTTPMessageConverter。

使用javaconfig,我们也不需要创建HibernateAwareObjectMapper,我们只需要将Hibernate4Module添加到Spring已经拥有的默认PingJackson2HttpMessageConverter中,并将其添加到应用程序的HttpMessageConverters中,因此我们需要:

  1. WebMvcConfigurerAdapter 扩展我们的 spring config 类,并覆盖 configureMessageConverters 的方法

  2. 在该方法上,添加MapingJackson2HttpMessageConverter,其中Hibernate4Module在previus方法中注册。

我们的配置类应如下所示:

@Configuration
@EnableWebMvc
public class MyConfigClass extends WebMvcConfigurerAdapter{

    //More configuration....

    /* Here we register the Hibernate4Module into an ObjectMapper, then set this custom-configured ObjectMapper
     * to the MessageConverter and return it to be added to the HttpMessageConverters of our application*/
    public MappingJackson2HttpMessageConverter jacksonMessageConverter(){
        MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();

        ObjectMapper mapper = new ObjectMapper();
        //Registering Hibernate4Module to support lazy objects
        mapper.registerModule(new Hibernate4Module());

        messageConverter.setObjectMapper(mapper);
        return messageConverter;

    }

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        //Here we add our custom-configured HttpMessageConverter
        converters.add(jacksonMessageConverter());
        super.configureMessageConverters(converters);
    }

    //More configuration....
}

如果你有一个xml配置,你也不需要创建自己的MapingJackson2HttpMessageConverter,但你确实需要创建教程中显示的个性化映射器(HibernateAwareObjectMapper),所以你的xml配置应该看起来像这样:

<mvc:message-converters>
    <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
        <property name="objectMapper">
            <bean class="com.pastelstudios.json.HibernateAwareObjectMapper" />
        </property>
    </bean>
</mvc:message-converters>

希望这个答案是可以理解的,并帮助某人找到这个问题的解决方案,任何问题请随时提出!


答案 2

从Spring 4.2开始,使用Spring Boot和javaconfig,注册Hibernate4Module现在就像将其添加到您的配置中一样简单:

@Bean
public Module datatypeHibernateModule() {
  return new Hibernate4Module();
}

编号: https://spring.io/blog/2014/12/02/latest-jackson-integration-improvements-in-spring