Envers is unable to detect a @OneToMany mapping with CompositeKey
ornitorrinc Sep 27, 2013 8:26 AMHi 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.