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

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

当我尝试获取这个用户时,我总是要加载所有的坐标来获取用户对象,否则当jackson尝试序列化用户时抛出exception:

com.fasterxml.jackson.databind.JsonMappingException:无法初始化代理 – 没有会话

这是因为jackson试图抓取这个无法取得的物体。 这里是对象:

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的答案。 但是可能用新的jacksonfunction来实现。

我的版本是:

  • spring3.2.5
  • hibernate4.1.7
  • jackson2.2

提前致谢。

我终于find了解决scheme! 感谢indybee给我一个线索。

Spring 3.1,Hibernate 4和Jackson-Module-Hibernate教程为Spring 3.1和更早版本提供了一个很好的解决scheme。 但是从版本3.1.2开始,Spring拥有自己的MappingJackson2HttpMessageConverter ,其function几乎与本教程中的一样,所以我们不需要创build这个自定义的HTTPMessageConverter。

使用javaconfig我们不需要创buildHibernateAwareObjectMapper ,我们只需要将Hibernate4Module添加到Spring已经具有的默认MappingJackson2HttpMessageConverter中 ,并将其添加到应用程序的HttpMessageConverters中,所以我们需要:

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

  2. 在该方法中,添加MappingJackson2HttpMessageConverter与在previus方法中注册的Hibernate4Module

我们的configuration类应该是这样的:

 @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.... } 

如果你有一个xmlconfiguration,你不需要创build你自己的MappingJackson2HttpMessageConverter,但你需要创build出现在本教程(HibernateAwareObjectMapper)中的个性化映射器,所以你的xmlconfiguration应该如下所示:

 <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> 

希望这个答案是可以理解的,并帮助有人find解决这个问题,任何问题随时问!

这与@rick接受的解决scheme类似。

如果您不想触摸现有的消息转换器configuration,则可以声明一个Jackson2ObjectMapperBuilder bean,如下所示:

 @Bean public Jackson2ObjectMapperBuilder configureObjectMapper() { return new Jackson2ObjectMapperBuilder() .modulesToInstall(Hibernate4Module.class); } 

不要忘记添加以下依赖到您的Gradle文件(或Maven):

 compile 'com.fasterxml.jackson.datatype:jackson-datatype-hibernate4:2.4.4' 

如果你有一个spring-boot应用程序,并且想要保持从application.properties文件修改Jacksonfunction的能力,那么这很有用。

从Spring 4.2开始,使用Spring Boot和javaconfig,注册Hibernate4Module现在就像添加到你的configuration一样简单:

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

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

如果您使用XMLconfiguration并使用<annotation-driven /> ,我发现您必须按照Jackson Github帐户中的build议在<annotation-driven>内部嵌套<message-converters>

像这样:

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

`

在Spring Data Rest的情况下,当@ r1ckr发布的解决scheme工作的时候,所需要的就是根据你的Hibernate版本添加下列依赖项之一:

 <dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-hibernate4</artifactId> <version>${jackson.version}</version> </dependency> 

要么

 <dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-hibernate5</artifactId> <version>${jackson.version}</version> </dependency> 

在Spring Data Rest中有一个类:

org.springframework.data.rest.webmvc.json.Jackson2DatatypeHelper

它将在应用程序启动时自动检测和注册模块。

然而有一个问题:

发行序列化Lazy @ManyToOne

对于那些来这里寻找解决scheme的基于Apache CXF的RESTful服务的人来说,修复它的configuration如下:

 <jaxrs:providers> <bean class="com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider"> <property name="mapper" ref="objectMapper"/> </bean> </jaxrs:providers> <bean id="objectMapper" class="path.to.your.HibernateAwareObjectMapper"/> 

HibernateAwareObjectMapper被定义为:

 public class HibernateAwareObjectMapper extends ObjectMapper { public HibernateAwareObjectMapper() { registerModule(new Hibernate5Module()); } } 

截至2016年6月,需要以下依赖项(假设您使用Hibernate5):

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

您可以使用Spring Data Rest项目中的以下帮助程序:

 Jackson2DatatypeHelper.configureObjectMapper(objectMapper); 

我试了@ rick的有用答案 ,但遇到了像“ jackson-datatype-jsr310 ”这样的“众所周知的模块”不会自动注册的问题,尽pipe它们在类path中。 (这篇博文解释了自动注册。)

扩展@ rick的答案,这里是使用Spring的Jackson2ObjectMapperBuilder创buildObjectMapper 。 这会自动注册“众所周知的模块”,并设置除安装Hibernate4Module之外的特定function。

 @Configuration @EnableWebMvc public class MyWebConfig extends WebMvcConfigurerAdapter { // get a configured Hibernate4Module // here as an example with a disabled USE_TRANSIENT_ANNOTATION feature private Hibernate4Module hibernate4Module() { return new Hibernate4Module().disable(Hibernate4Module.Feature.USE_TRANSIENT_ANNOTATION); } // create the ObjectMapper with Spring's Jackson2ObjectMapperBuilder // and passing the hibernate4Module to modulesToInstall() private MappingJackson2HttpMessageConverter jacksonMessageConverter(){ Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder() .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) .modulesToInstall(hibernate4Module()); return new MappingJackson2HttpMessageConverter(builder.build()); } @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { converters.add(jacksonMessageConverter()); super.configureMessageConverters(converters); } } 

虽然这个问题与这个问题略有不同: 在序列化Hibernate对象时引发了奇怪的Jacksonexception ,但是可以用相同的方式修复底层问题:

 @Provider public class MyJacksonJsonProvider extends JacksonJsonProvider { public MyJacksonJsonProvider() { ObjectMapper mapper = new ObjectMapper(); mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); setMapper(mapper); } } 

我试过了,工作:

//延迟加载的自定义configuration

 public static class HibernateLazyInitializerSerializer extends JsonSerializer<JavassistLazyInitializer> { @Override public void serialize(JavassistLazyInitializer initializer, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException { jsonGenerator.writeNull(); } } 

并configuration映射器:

  mapper = new JacksonMapper(); SimpleModule simpleModule = new SimpleModule( "SimpleModule", new Version(1,0,0,null) ); simpleModule.addSerializer( JavassistLazyInitializer.class, new HibernateLazyInitializerSerializer() ); mapper.registerModule(simpleModule);