我有这种@OneToOne Hibernate relationShip
public class Address implements Serializable {
private String id;
private String city;
private String country;
//setter getters ommitted
}
public class Student implements Serializable {
private String id;
private String firstName;
private String lastName;
private Address address;
}
地址项目被映射为LAZY。
现在我想使用
获取用户及其地址session.load(Student.class,id);
在我的daoService中。
然后我将其作为JSON从我的Spring MVC控制器返回:
@RequestMapping(value="/getStudent.do",method=RequestMethod.POST)
@ResponseBody
public Student getStudent(@RequestParam("studentId") String id){
Student student = daoService.getStudent(id);
return student;
}
不幸的是,由于Lazy clasees而无法正常工作,我失败了:
org.codehaus.jackson.map.JsonMappingException: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: com.vanilla.objects.Student_$$_javassist_1["address"]->com.vanilla.objects.Address_$$_javassist_0["handler"])
at org.codehaus.jackson.map.ser.StdSerializerProvider$1.serialize(StdSerializerProvider.java:62)
我确实使用OpenSessionInViewInterceptor,它工作得很好。 我知道我可以使用左连接HQL查询并检索学生并解决这个问题并解决问题。我也明白,改变与EAGER的关系将解决它。
但是如何使用标准的jackson消息转换器序列化为JSON惰性类,这是因为我添加到了我的XML文件中。
答案 0 :(得分:6)
最简单的解决方案:不要序列化实体,使用值对象。
如果这不适合您,请确保已分离实体Object。
使用JPA(2),您可以使用EntityManager.detach(entity)
,使用普通的Hibernate,等效的是Session.evict(entity)
。
答案 1 :(得分:5)
一旦我编写处理器来处理这个问题,但现在可以使用jackson hibernate module轻松解决此问题。
答案 2 :(得分:4)
在您的DAO方法中添加Hibernate.initialize(<your getter method>);
来解决此问题。
Student student = findById(<yourId>);
Hibernate.initialize(student.getAddress());
...
return student;
尝试上述方法。
答案 3 :(得分:0)
还有另一种选择可以解决您的问题。您可以在web.xml中添加此过滤器
<filter>
<filter-name>springOpenEntityManagerInViewFilter</filter-name>
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
<init-param>
<param-name>entityManagerFactoryBeanName</param-name>
<param-value>entityManagerFactory</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>springOpenEntityManagerInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
问题是实体加载延迟并且序列化在完全加载之前发生。
答案 4 :(得分:0)
但是如何使用标准的jackson序列化为JSON惰性类 消息转换器,因为我添加到我的XML文件中。
首先,我建议不要使用DTO / Value Object 来解决此问题。
您可能会在开始时发现它很容易,但在每次新的开发/更改时,重复的代码意味着每次都要进行两次修改...否则会出现错误。
我并不是说VO或DTO是难闻的气味,但你应该将它们用于设计它们的原因(例如根据逻辑层提供不同的内容/结构或解决无法解决的序列化问题)。
如果您有一个干净有效的方法来解决没有VO / DTO的序列化问题而您不需要它们,请不要使用它们。
关于它,当你使用Jackson和Hibernate实体时,有很多方法可以解决延迟加载问题。
实际上,最简单的方法是使用FasterXML/jackson-datatype-hibernate
构建Jackson模块(jar)以支持JSON序列化的项目 和Hibernate的反序列化(http://hibernate.org)具体 数据类型和属性;特别是懒惰的方面。
它提供了Hibernate3Module/Hibernate4Module/Hibernate5Module
,可以在ObjectMapper
注册的扩展模块,以提供与Hibernate特性相关的明确定义的扩展集。
要做到这一点,你只需要添加所需的依赖项并添加
杰克逊模块可在需要的处理过程中使用。
如果您使用Hibernate 3:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-hibernate3</artifactId>
<version>${jackson.version.datatype}</version>
</dependency>
如果您使用Hibernate 4:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-hibernate4</artifactId>
<version>${jackson.version.datatype}</version>
</dependency>
等等......
使用的Jackson版本和ackson-datatype扩展名的jackson.version.datatype
应该相同。
如果你使用或可能使用Spring Boot,你只需要将模块声明为特定Configuration
类或SpringBootApplication
类中的bean,它将自动注册任何Jackson { {1}}已创建。
74.3 Customize the Jackson ObjectMapper
Spring Boot部分声明:
ObjectMapper
类型的任何bean都将是 自动注册自动配置com.fasterxml.jackson.databind.Module
并应用于任何Jackson2ObjectMapperBuilder
个实例 它创造了。这提供了一种全球性的贡献机制 向应用程序添加新功能时的自定义模块。
例如:
ObjectMapper
或:
@Configuration
public class MyJacksonConfig {
@Bean
public Module hibernate5Module() {
return new Hibernate5Module();
}
}