2016-01-06 2 views
1

Я понимаю, что когда Hibernate загружает одно из моих сущностей из базы данных, ему необходимо построить новый экземпляр объекта, используя что-то , аналогичное - Class.newInstance().Альтернативы No-Args Constructor

Таким образом, Hibernate будет жаловаться, когда он пытается сериализовать классы, которые не выставляют конструктор без 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 для обработки сериализации/десериализации этого типа. Это похоже на полный перебор, нет никакой индивидуальной логики сериализации в per se, и я не заинтересован в написании пользовательских nullSafeSet/nullSafeGet.

ответ

3

Вы можете создать org.hibernate.Interceptor.

Этот интерфейс имеет способ instantiate(), который затем использует Hibernate для создания экземпляров объектов.

0

Еще один способ взглянуть на пакет org.hibernate.tuple.

Вы можете создать пользовательскую сущность org.hibernate.tuple.Tuplizer и обычай org.hibernate.tuple.Instantiator. Tuplizer будет фабрикой для экземпляров вашего cоздателя экземпляров, и вы можете зарегистрировать его в org.hibernate.cfg.Configuration, что создает сессионный завод что-то вроде:

Configuration conf = new Configuration(); 
... 
conf.getEntityTuplizerFactory().registerDefaultTuplizerClass(EntityMode.POJO, MyPojoEntityTuplizer.class); 
... 
SessionFactory sessionFactory = conf.buildSessionFactory(); 

cоздателя экземпляры могут быть что-то вроде этого:

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); 
    } 

    ... 
} 
0

Hibernate (и JPA, потому что он требует конструкторов no-arg в спецификации) немного ограничен, когда речь заходит о настройке создания экземпляров сущностей. Надеемся, что в последующих версиях Hibernate и JPA все изменится.

Вы можете использовать перехватчики Hibernate или инсталяторы для этого (как уже указывалось в других ответах). Имейте в виду, что тогда эта ленивая загрузка экземпляров Person не будет работать, потому что Hibernate не сможет создать для них прокси.

Решение, которое не предполагает изменения каких-либо механизмов Инстанциация создать подкласс Person, который не обеспечивает конструктор без аргументов:

public class PersonEntity extends Person { 
    public PersonEntity() { 
     super(null, null); 
    } 
} 

Поскольку Person класс из внешней библиотеки, то вы должны используйте xml для его сопоставления. Если вы используете JPA xml, просто укажите, что это mapped-superclass. Если вы используете hbm.xml, то (интересно) вещи немного сложнее, см. this answer для более подробной информации.