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.