0 Replies Latest reply on Sep 27, 2013 8:26 AM by ornitorrinc

    Envers is unable to detect a @OneToMany mapping with CompositeKey

    ornitorrinc

      Hi everybody,

       

      These are the mapped entities:

       

      import java.util.List;
      
      import javax.persistence.Column;
      import javax.persistence.Entity;
      import javax.persistence.EnumType;
      import javax.persistence.Enumerated;
      import javax.persistence.GeneratedValue;
      import javax.persistence.Id;
      import javax.persistence.JoinColumn;
      import javax.persistence.ManyToOne;
      import javax.persistence.OneToMany;
      import javax.persistence.Table;
      import javax.xml.bind.annotation.XmlRootElement;
      import javax.xml.bind.annotation.XmlTransient;
      import javax.xml.bind.annotation.XmlType;
      
      import org.hibernate.annotations.GenericGenerator;
      import org.hibernate.annotations.Type;
      import org.hibernate.envers.AuditMappedBy;
      import org.hibernate.envers.Audited;
      import org.hibernate.envers.RelationTargetAuditMode;
      import org.joda.time.LocalDate;
      
      import es.gc.epsilon.core.commons.enums.GenderEnum;
      
      @XmlType
      @XmlRootElement
      @Entity
      @Audited
      @Table(name = PersonEntity.TABLE_NAME)
      public class PersonEntity extends AbstractEntity {
      
        private static final long serialVersionUID = 1L;
      
        /* TABLE */
        public static final String TABLE_NAME = "EP_PERSON";
      
        /* COLUMNS */
        public static final String ID_PERSON_COLUMN = "ID_PERSON";
        public static final String ID_EMPLOYEE_COLUMN = "ID_EMPLOYEE";
        public static final String SURNAME_COLUMN = "SURNAME";
        public static final String NAME_COLUMN = "NAME";
        public static final String SECOND_SURNAME_COLUMN = "SECOND_SURNAME";
        public static final String ACRONYM_COLUMN = "ACRONYM";
        public static final String PERSONAL_ID_TYPE_COLUMN = "ID_PERSONAL_ID_TYPE";
        public static final String BIRTHDAY_COLUMN = "BIRTHDAY";
        public static final String GENDER_COLUMN = "GENDER";
      
        private String idPerson;
        private PersonalIdTypeEntity personalIdType;
        private String name;
        private String secondSurname;
        private String surname;
        private String acronym;
        private LocalDate birthday;
        private GenderEnum gender;
        private List<EmployeeEntity> employees;
        private List<PersonalAddressEntity> addresses;
        private List<PersonalPhoneEntity> personalPhones;
      
        @Column(name = ACRONYM_COLUMN)
        public String getAcronym() {
          return acronym;
        }
      
        @OneToMany(mappedBy = "idPerson")
        public List<PersonalAddressEntity> getAddresses() {
          return addresses;
        }
      
        @Column(name = BIRTHDAY_COLUMN)
        @Type(type = JODA_LOCAL_TIME_JPA_CONVERTER)
        public LocalDate getBirthday() {
          return birthday;
        }
      
        @XmlTransient
        @OneToMany(mappedBy = "person")
        public List<EmployeeEntity> getEmployees() {
          return employees;
        }
      
        @Column(name = GENDER_COLUMN, columnDefinition = "char")
        @Enumerated(EnumType.STRING)
        public GenderEnum getGender() {
          return gender;
        }
      
        @Column(name = ID_PERSON_COLUMN, nullable = false, updatable = false, length = 36)
        @Id
        @GeneratedValue(generator = UUID_GENERATOR_NAME)
        @GenericGenerator(name = UUID_GENERATOR_NAME, strategy = UUID_GENERATOR_STRATEGY)
        public String getIdPerson() {
          return idPerson;
        }
      
        @Column(name = NAME_COLUMN)
        public String getName() {
          return name;
        }
      
        @Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
        @ManyToOne
        @JoinColumn(name = PERSONAL_ID_TYPE_COLUMN, referencedColumnName = PersonalIdTypeEntity.ID_PERSONAL_ID_TYPE_COLUMN)
        public PersonalIdTypeEntity getPersonalIdType() {
          return personalIdType;
        }
      
        @OneToMany(mappedBy = "idPerson")
        public List<PersonalPhoneEntity> getPersonalPhones() {
          return personalPhones;
        }
      
        @Column(name = SECOND_SURNAME_COLUMN)
        public String getSecondSurname() {
          return secondSurname;
        }
      
        @Column(name = SURNAME_COLUMN)
        public String getSurname() {
          return surname;
        }
      
        public void setAcronym(String acronym) {
          this.acronym = acronym;
        }
      
        public void setAddresses(List<PersonalAddressEntity> addresses) {
          this.addresses = addresses;
        }
      
        public void setBirthday(LocalDate birthday) {
          this.birthday = birthday;
        }
      
        public void setEmployees(List<EmployeeEntity> employees) {
          this.employees = employees;
        }
      
        public void setGender(GenderEnum gender) {
          this.gender = gender;
        }
      
        public void setIdPerson(String idPerson) {
          this.idPerson = idPerson;
        }
      
        public void setName(String name) {
          this.name = name;
        }
      
        public void setPersonalIdType(PersonalIdTypeEntity personalIdType) {
          this.personalIdType = personalIdType;
        }
      
        public void setPersonalPhones(List<PersonalPhoneEntity> personalPhones) {
          this.personalPhones = personalPhones;
        }
      
        public void setSecondSurname(String secondSurname) {
          this.secondSurname = secondSurname;
        }
      
        public void setSurname(String surname) {
          this.surname = surname;
        }
      
        @Override
        public String toString() {
          return "PersonEntity " + ENTITY_CONTENT_OPENING_DELIMITER + "idPerson=" + idPerson
              + ENTITY_CONTENT_CLOSING_DELIMITER;
        }
      
      }
      

       

      import java.io.Serializable;
      
      import javax.persistence.Column;
      import javax.persistence.Entity;
      import javax.persistence.Id;
      import javax.persistence.IdClass;
      import javax.persistence.JoinColumn;
      import javax.persistence.ManyToOne;
      import javax.persistence.Table;
      import javax.xml.bind.annotation.XmlRootElement;
      import javax.xml.bind.annotation.XmlTransient;
      import javax.xml.bind.annotation.XmlType;
      
      import org.hibernate.envers.Audited;
      
      @XmlType
      @XmlRootElement
      @Entity
      @Audited
      @Table(name = PersonalAddressEntity.TABLE_NAME)
      @IdClass(PersonalAddressEntity.Key.class)
      public class PersonalAddressEntity extends AbstractBasicAddressEntity {
      
        @XmlTransient
        public static class Key implements Serializable {
      
          private static final long serialVersionUID = 1L;
      
          private String idPerson;
          private String adressType;
      
          public Key() {
            super();
          }
      
          public Key(String idPerson, String adressType) {
            super();
            this.setIdPerson(idPerson);
            this.setAdressType(adressType);
          }
      
          public String getAdressType() {
            return adressType;
          }
      
          public String getIdPerson() {
            return idPerson;
          }
      
          public void setAdressType(String adressType) {
            this.adressType = adressType;
          }
      
          public void setIdPerson(String idPerson) {
            this.idPerson = idPerson;
          }
      
        }
      
        private static final long serialVersionUID = 1L;
      
        /* TABLE */
        public static final String TABLE_NAME = "EP_PERSONAL_ADDRESS";
      
        /* COLUMNS */
        public static final String ID_PERSON_COLUMN = "ID_PERSON";
        public static final String ADDRESS_TYPE_COLUMN = "ADDRESS_TYPE";
        public static final String MAIN_ADRESS = "MAIN_ADDRESS";
      
        private PersonEntity idPerson;
        private String adressType;
        private Boolean mainAddress;
      
        public PersonalAddressEntity() {
        }
      
        @Id
        @Column(name = ADDRESS_TYPE_COLUMN, insertable = false, updatable = false)
        public String getAdressType() {
          return adressType;
        }
      
        @Id
        @XmlTransient
        @ManyToOne(targetEntity = PersonEntity.class)
        @JoinColumn(name = ID_PERSON_COLUMN, referencedColumnName = PersonEntity.ID_PERSON_COLUMN)
        public PersonEntity getIdPerson() {
          return idPerson;
        }
      
        @Column(name = MAIN_ADRESS, columnDefinition = "BIT", length = 1)
        public Boolean getMainAddress() {
          return mainAddress;
        }
      
        public void setAdressType(String adressType) {
          this.adressType = adressType;
        }
      
        public void setIdPerson(PersonEntity idPerson) {
          this.idPerson = idPerson;
        }
      
        public void setMainAddress(Boolean mainAddress) {
          this.mainAddress = mainAddress;
        }
      
        @Override
        public String toString() {
          return "PersonalAddressEntity " + ENTITY_CONTENT_OPENING_DELIMITER + "idPerson=" + idPerson
              + ENTITY_CONTENT_CLOSING_DELIMITER;
        }
      }
      

       

       

      And I get this error when deploying:

       

      Caused by: org.hibernate.MappingException: Unable to read the mapped by attribute for addresses in es.gc.epsilon.core.domain.PersonalAddressEntity!
          at org.hibernate.envers.configuration.metadata.CollectionMetadataGenerator.getMappedBy(CollectionMetadataGenerator.java:642)
          at org.hibernate.envers.configuration.metadata.CollectionMetadataGenerator.addOneToManyAttached(CollectionMetadataGenerator.java:187)
          at org.hibernate.envers.configuration.metadata.CollectionMetadataGenerator.addCollection(CollectionMetadataGenerator.java:169)
          at org.hibernate.envers.configuration.metadata.AuditMetadataGenerator.addValueInSecondPass(AuditMetadataGenerator.java:223)
          at org.hibernate.envers.configuration.metadata.AuditMetadataGenerator.addValue(AuditMetadataGenerator.java:245)
          at org.hibernate.envers.configuration.metadata.AuditMetadataGenerator.addProperties(AuditMetadataGenerator.java:258)
          at org.hibernate.envers.configuration.metadata.AuditMetadataGenerator.generateSecondPass(AuditMetadataGenerator.java:519)
          at org.hibernate.envers.configuration.EntitiesConfigurator.configure(EntitiesConfigurator.java:114)
          at org.hibernate.envers.configuration.AuditConfiguration.<init>(AuditConfiguration.java:114)
          at org.hibernate.envers.configuration.AuditConfiguration.getFor(AuditConfiguration.java:164)
          at org.hibernate.envers.event.EnversIntegrator.integrate(EnversIntegrator.java:64)
          at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:303)
          at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1750)
          at org.hibernate.ejb.EntityManagerFactoryImpl.<init>(EntityManagerFactoryImpl.java:94)
          at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:920)
          ... 9 more
      

       

       

      If I try to add the @AuditMappedBy annotation like that:

       

        @OneToMany(mappedBy = "idPerson")
        @AuditMappedBy(mappedBy = "idPerson")
        public List<PersonalAddressEntity> getAddresses() {
          return addresses;
        }
      

       

       

      I get this error while deploying:

       

      Caused by: org.hibernate.MappingException: @AuditMappedBy points to a property that doesn't exist: es.gc.epsilon.core.domain.PersonalAddressEntity.idPerson
          at org.hibernate.envers.configuration.ClassesAuditingData.forcePropertyInsertable(ClassesAuditingData.java:84)
          at org.hibernate.envers.configuration.ClassesAuditingData.updateCalculatedFields(ClassesAuditingData.java:70)
          at org.hibernate.envers.configuration.EntitiesConfigurator.configure(EntitiesConfigurator.java:85)
          at org.hibernate.envers.configuration.AuditConfiguration.<init>(AuditConfiguration.java:114)
          at org.hibernate.envers.configuration.AuditConfiguration.getFor(AuditConfiguration.java:164)
          at org.hibernate.envers.event.EnversIntegrator.integrate(EnversIntegrator.java:64)
          at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:303)
          at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1750)
          at org.hibernate.ejb.EntityManagerFactoryImpl.<init>(EntityManagerFactoryImpl.java:94)
          at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:920)
      

       

       

      From my point of view, it seems a bug related to:
      [HHH-7625] Inverse OneToMany with a CompositeKey fails - Hibernate JIRA

       

      Do you think I'm right or I'm doing something wrong?

       

      I'll appreciate any help, thanks in advance.