据我所知,当Hibernate从数据库加载我的一个实体时,有必要使用类似到Class.newInstance()
的东西来构造对象的新实例。
因此,Hibernate在尝试序列化不暴露no-args构造函数的类时会抱怨:
javax.persistence.PersistenceException: org.hibernate.InstantiationException: No default constructor for entity: : com.acme.Person
让我们假设com.acme.Person
是来自外部第三方库的类。这意味着我无法改变类的定义,并且无法按要求添加默认构造函数。
我有什么选择?
从概念的角度来看,如果我能为Hibernate提供一个工厂,它会很棒,例如:
public class PersonFactory implements Factory<Person> {
public Person create() {
// ctor takes firstName, lastName
return new Person(null, null);
}
}
使用此Person
实例,Hibernate将能够使用标准反射技术重新设置成员变量(在本例中为firstName
和lastName
)从数据库加载。
我找到了关于使用自定义UserType
来处理此类型的序列化/反序列化的注释。这似乎完全矫枉过正,本身没有自定义序列化逻辑,我也没兴趣编写自定义nullSafeSet
/ nullSafeGet
。
答案 0 :(得分:3)
您可以创建org.hibernate.Interceptor
。
这个接口有一个方法instantiate()
,Hibernate然后用它来创建实体的实例。
答案 1 :(得分:0)
另一种方法是查看org.hibernate.tuple
包。
您可以创建自定义实体org.hibernate.tuple.Tuplizer
和自定义org.hibernate.tuple.Instantiator
。 Tuplizer将是Instantiator实例的工厂,您可以将其注册到创建会话工厂的org.hibernate.cfg.Configuration
,例如:
Configuration conf = new Configuration();
...
conf.getEntityTuplizerFactory().registerDefaultTuplizerClass(EntityMode.POJO, MyPojoEntityTuplizer.class);
...
SessionFactory sessionFactory = conf.buildSessionFactory();
Instantiator可以是这样的:
public class FactoryBasedPojoEntityInstantiator implements Instantiator {
private Class<?> entityClass;
public Bo2PojoEntityInstantiator(PersistentClass persistentClass) {
this.entityClass = persistentClass.getMappedClass();
}
public Object instantiate(Serializable id) {
return Factory.create(entityClass);
}
...
}
答案 2 :(得分:0)
Hibernate(和JPA,因为它在规范中需要no-arg构造函数)在定制实体实例的创建方面有点受限。希望在后续版本的Hibernate和JPA标准中,事情会发生变化。
您可以使用Hibernate拦截器或实例化器(正如其他答案中已经指出的那样)。请记住,Person
实例的延迟加载将不起作用,因为Hibernate将无法为它们创建代理。
不涉及更改任何实例化机制的解决方案是创建Person
的子类,它提供no-arg构造函数:
public class PersonEntity extends Person {
public PersonEntity() {
super(null, null);
}
}
由于Person
是来自外部库的类,因此您必须使用xml来映射它。如果您使用JPA xml,那么只需指出它是mapped-superclass
。如果您使用hbm.xml
,那么(有趣的是)事情会更复杂一些,有关详细信息,请参阅this answer。