r1c*_*ckr 75 java serialization spring hibernate jackson
我有一个简单的控制器返回一个User对象,这个用户的属性坐标有hibernate属性FetchType.LAZY.
当我尝试获取此用户时,我总是必须加载所有坐标以获取用户对象,否则当Jackson尝试序列化时,用户会抛出异常:
com.fasterxml.jackson.databind.JsonMappingException:无法初始化代理 - 没有会话
这是因为杰克逊试图获取这个未被攻击的对象.这是对象:
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;
}
Run Code Online (Sandbox Code Playgroud)
和控制器:
@RequestMapping(value = "/user/{username}", method=RequestMethod.GET)
public @ResponseBody User getUser(@PathVariable String username) {
User user = userService.getUser(username);
return user;
}
Run Code Online (Sandbox Code Playgroud)
有办法告诉杰克逊不要序列化未被攻击的物体吗?我一直在寻找3年前发布的其他答案实现jackson-hibernate-module.但可能通过新的杰克逊功能可以实现.
我的版本是:
提前致谢.
r1c*_*ckr 90
我终于找到了解决方案!感谢indybee给我一个线索.
Spring 3.1,Hibernate 4和Jackson-Module-Hibernate教程为Spring 3.1和早期版本提供了一个很好的解决方案.但是,自3.1.2版本以来,Spring拥有自己的MappingJackson2HttpMessageConverter,它具有与教程中几乎相同的功能,因此我们不需要创建这个自定义HTTPMessageConverter.
使用javaconfig我们也不需要创建HibernateAwareObjectMapper,我们只需要将Hibernate4Module添加到Spring已经拥有的默认MappingJackson2HttpMessageConverter并将其添加到应用程序的HttpMessageConverters中,因此我们需要:
从WebMvcConfigurerAdapter扩展我们的spring配置类并覆盖configureMessageConverters方法.
在该方法上添加MappingJackson2HttpMessageConverter和在previus方法中注册的Hibernate4Module.
我们的配置类应如下所示:
@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....
}
Run Code Online (Sandbox Code Playgroud)
如果你有一个xml配置,你也不需要创建自己的MappingJackson2HttpMessageConverter,但你需要创建教程中出现的个性化映射器(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>
Run Code Online (Sandbox Code Playgroud)
希望这个答案是可以理解的,并帮助有人找到解决这个问题的方法,任何问题随时都可以问!
chr*_*arx 28
从Spring 4.2开始,使用Spring Boot和javaconfig,现在注册Hibernate4Module就像在配置中添加它一样简单:
@Bean
public Module datatypeHibernateModule() {
return new Hibernate4Module();
}
Run Code Online (Sandbox Code Playgroud)
REF:https://spring.io/blog/2014/12/02/latest-jackson-integration-improvements-in-spring
小智 14
这类似于@rick接受的解决方案.
如果您不想触及现有的消息转换器配置,您可以只声明一个Jackson2ObjectMapperBuilder
bean:
@Bean
public Jackson2ObjectMapperBuilder configureObjectMapper() {
return new Jackson2ObjectMapperBuilder()
.modulesToInstall(Hibernate4Module.class);
}
Run Code Online (Sandbox Code Playgroud)
不要忘记将以下依赖项添加到Gradle文件(或Maven):
compile 'com.fasterxml.jackson.datatype:jackson-datatype-hibernate4:2.4.4'
Run Code Online (Sandbox Code Playgroud)
如果您有一个spring-boot应用程序并且希望保留从application.properties
文件修改Jackson功能的功能,则非常有用.
我花了一整天的时间试图解决同样的问题。您无需更改现有消息转换器配置即可完成此操作。
在我看来,在jackson-datatype-hibernate的帮助下,解决这个问题的最简单方法只需 2 个步骤:
kotlin 示例(与 java 相同):
build.gradle.kts
:implementation("com.fasterxml.jackson.datatype:jackson-datatype-hibernate5:$jacksonHibernate")
Run Code Online (Sandbox Code Playgroud)
@Bean
@Bean
fun hibernate5Module(): Module = Hibernate5Module()
Run Code Online (Sandbox Code Playgroud)
注意,Module
是com.fasterxml.jackson.databind.Module
,不是java.util.Module
另外一个好的做法是将@JsonBackReference
&添加@JsonManagedReference
到@OneToMany
&@ManyToOne
关系中。@JsonBackReference
班级里可能只有1个人。
在Spring Data Rest的情况下,当@ r1ckr发布的解决方案有效时,所需要的只是根据您的Hibernate版本添加以下依赖项之一:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-hibernate4</artifactId>
<version>${jackson.version}</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)
要么
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-hibernate5</artifactId>
<version>${jackson.version}</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)
在Spring Data Rest中有一个类:
org.springframework.data.rest.webmvc.json.Jackson2DatatypeHelper
它将在应用程序启动时自动检测并注册模块.
但是有一个问题:
如果您使用XML配置和使用<annotation-driven />
,我发现您有窝<message-converters>
内<annotation-driven>
的建议杰克逊Github上的帐户.
像这样:
<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>
Run Code Online (Sandbox Code Playgroud)
`
以下解决方案适用于 Spring 4.3(非引导)和 Hibernate 5.1,出于性能原因,我们将所有 fetchtypes 转换为fetch=FetchType.LAZY
from case fetch=FetchType.EAGER
。com.fasterxml.jackson.databind.JsonMappingException: could not initialize proxy
由于延迟加载问题,我们立即看到了异常。
首先,我们添加以下maven依赖:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-hibernate5</artifactId>
</dependency>
Run Code Online (Sandbox Code Playgroud)
然后将以下内容添加到我们的 Java MVC 配置文件中:
@Configuration
@EnableWebMvc
public class MvcConfig extends WebMvcConfigurerAdapter {
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
Hibernate5Module h5module = new Hibernate5Module();
h5module.disable(Hibernate5Module.Feature.USE_TRANSIENT_ANNOTATION);
h5module.enable(Hibernate5Module.Feature.FORCE_LAZY_LOADING);
for (HttpMessageConverter<?> mc : converters){
if (mc instanceof MappingJackson2HttpMessageConverter || mc instanceof MappingJackson2XmlHttpMessageConverter) {
((AbstractJackson2HttpMessageConverter) mc).getObjectMapper().registerModule(h5module);
}
}
return;
}
Run Code Online (Sandbox Code Playgroud)
笔记:
您需要创建并配置 Hibernate5Module 才能获得与没有此模块的 Jackson 类似的行为。默认值做出了不兼容的假设。
我们的WebMvcConfigurerAdapter
里面有很多其他配置,我们想避免另一个配置类,这就是为什么我们没有使用WebMvcConfigurationSupport#addDefaultHttpMessageConverters
其他帖子中提到的函数。
WebMvcConfigurerAdapter#configureMessageConverters
禁用 Spring 消息转换器的所有内部配置。我们宁愿避免与此相关的潜在问题。
使用extendMessageConverters
对所有自动配置的 Jackson 类的启用访问,而不会丢失所有其他消息转换器的配置。
使用getObjectMapper#registerModule
我们能够将其添加Hibernate5Module
到现有的转换器中。
此添加解决了 Hibernate 和延迟加载的问题,但导致了生成的 JSON 格式的残留问题。正如本 github 问题中所报告的,hibernate-jackson 延迟加载模块当前忽略 @JsonUnwrapped 注释,从而导致潜在的数据错误。无论强制加载功能设置如何,都会发生这种情况。这个问题自2016年以来就一直存在。
笔记
看来,通过将以下内容添加到延迟加载的类中,内置 ObjectMapper 无需添加 hibernate5 模块即可工作:
@JsonIgnoreProperties( {"handler","hibernateLazyInitializer"} )
public class Anyclass {
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
66414 次 |
最近记录: |