Странное поведение JPA, инициализированное поле равно нулю

Я наблюдаю очень странное поведение с классом сущности и загружаю объект этого класса с JPA (hibernate entitymanager 3.3.1.ga). Класс имеет (встроенное) поле, которое инициализируется в объявлении. Установщик поля реализует нулевую проверку (т.е. Генерирует исключение, когда задано значение null).

...
@Entity
public class Participant extends BaseEntity implements Comparable<Participant> {
   ...
    @Embedded
 private AmsData amsData = new AmsData();

 public void setAmsData(AmsData amsData) {
  Checks.verifyArgNotNull(amsData, "amsdata");
  this.amsData = amsData;
 }
    ...
}

Когда я получаю этот объект с JPA, поле имеет значение NULL, если в db нет данных для полей, указанных во встроенном объекте.

...
public class ParticipantJpaDao implements ParticipantDao {
 @PersistenceContext
 private EntityManager em;

 @Override
 public Participant getParticipant(Long id) {
  return em.find(Participant.class, id);
 }
    ...
}

Я отлаживал процесс с точкой наблюдения в поле (должен останавливаться, когда к нему обращались или изменялись), и я вижу одну модификацию, когда поле инициализируется, но когда я получаю результат от вызова поиска, это поле нуль.

Может кто-нибудь объяснить, почему это так? Как я могу гарантировать, что поле не является нулевым, также когда нет данных для полей внедренных объектов в db (кроме того, чтобы установить его вручную после вызова поиска).

Ответ 1

Спецификация JPA явно не говорит о том, как обрабатывать набор столбцов, представляющих вложенный объект, все пустые. Он может сигнализировать нулевую ссылку или экземпляр объекта со всеми полями нуля. Hibernate выбирает нулевую ссылку в этом случае, хотя другие реализации JPA могут выбрать более позднюю.

Причина, по которой ваш сеттер никогда не вызывается, заключается в том, что Hibernate обращается к вашему полю через отражение, минуя сеттер, который вы внедрили. Это делается потому, что вы используете доступ на основе поля, а не доступ на основе свойств.

Ответ Чада предоставит вам необходимую функциональность, но есть оговорка (см. ниже).

"... Постоянное состояние объекта к нему поступает упорство время выполнения поставщика [1] либо через Атрибуты свойств стиля JavaBeans или через переменные экземпляра. Один тип доступа (доступ к полю или собственности) применяется к иерархии объектов. когда используются аннотации, размещение аннотации отображения на постоянные поля или постоянные свойства класса сущности определяет тип доступа как либо доступ на основе поля или имущества соответственно..." [ejb3 persistence спецификации]

поэтому, перемещая аннотации вниз к установщику, вы сообщаете JPA, что хотите использовать доступ на основе свойств вместо доступа на основе поля. Однако вы должны знать, что доступ на основе поля - как вы его реализуете в настоящее время - предпочтительнее доступа на основе свойств. Есть пара причин, почему доступ на основе свойств обескуражен, но каждый из них заключается в том, что вы вынуждены добавлять геттеры и сеттеры для всех ваших постоянных полей сущностей, но вы можете не захотеть, чтобы те же самые поля были подвержены мутации внешним клиентам. Другими словами, использование доступа на основе свойств JPA заставляет вас ослабить инкапсуляцию объекта.

Ответ 2

Ответ (спасибо rcampell), если все данные внедренного объекта равны нулю (в db), внедренный объект также будет нулевым, хотя, если он инициализируется в объявлении. Единственное решение, похоже, заключается в установке объекта вручную.

@Override
public Participant getParticipant(Long id) {
    Participant participant = em.find(Participant.class, id);
    if(participant != null && participant.getAmsData() == null)
    {
        participant.setAmsData(new AmsData());
    }
    return participant;
}

Мне все еще кажется странным...

Ответ 3

Хорошо, возможно, что ваш объект может быть сконструирован дважды за кулисами. Реализации JPA обычно устанавливают эти поля напрямую.

Думаю, вам нужно поставить аннотации на Getters и seters сами, если вы хотите, чтобы их использовали. См. Ответ:

Пустые конструкторы и сеттеры в JPA Entites