No-Args构造函数的替代方案

时间:2016-01-06 11:36:47

标签: java hibernate

据我所知,当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将能够使用标准反射技术重新设置成员变量(在本例中为firstNamelastName)从数据库加载。

我找到了关于使用自定义UserType来处理此类型的序列化/反序列化的注释。这似乎完全矫枉过正,本身没有自定义序列化逻辑,我也没兴趣编写自定义nullSafeSet / nullSafeGet

3 个答案:

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