Hello,
I'm new to your issue tracking system and at first I would like to thank you for your years of working on hibernate.
I have JPA-Entities with composite primary keys ( and therefore composite foreign keys ). They consist of (Id : String, ClientId : String) and the Id-Class is not mapped as embedded. {code} public interface CLId extends Serializable { /** * The unique id of the entity * * @return the id */ public String getId(); /** * The client id of the entity * * @return the client id */ public String getClientId();
} {code} {code} /** * Gruppe entity id class. * @see Gruppe */ @SuppressWarnings("all") public class _GruppeId implements CLId {
@Column(name = "ID") private String Id;
@Column(name = "CLIENTID") private String ClientId; public _GruppeId() {} public _GruppeId(String aId, String aClientId) { setId(aId); setClientId(aClientId); } public String getId() { return Id; }
public void setId(String aId) { this.Id = aId; }
public String getClientId() {
return ClientId; }
public void setClientId(String aClientId) { ClientId = aClientId; }
public boolean equals(Object o) { return ((o instanceof _GruppeId) && getId().equals(((_GruppeId)o).getId()) && getClientId().equals(((_GruppeId) o).getClientId())); }
public int hashCode() { return Id.hashCode() + getClientId().hashCode(); }
@Override public String toString() { Class<?> clazz = getClass(); return clazz.getSimpleName() + "@Id=" + getId() + ",ClientId=" + getClientId(); } } {code} {code} @MappedSuperclass @Table(indexes={ @Index(columnList="LOCK_VERSION") }) public class EntityImpl { /** * Implementation for access to business methods */ protected transient EntityBL ivEntityBL = null;
/** * primary key of the entity */ @Id @Column(name = "ID") private String Id;
/** * lock version for optimistic locking */ @Version @Column(name = "LOCK_VERSION") private int Lock_Version;
protected EntityImpl(int aParam) { super(); }
public void createEntityBL() { }
public <T extends Entity> void init(EntityInit<T> aInitializer) {
MonitoringProbe probe = Log4jMonitoringProbe.start(getClass().getName(), EntityImpl.class.getName() + ".init(EntityInitializer)"); try { if (getEntityBL() != null) { getEntityBL().init(); } if (aInitializer != null) { aInitializer.init((T)this); } } catch (RuntimeException e) { probe.setFailed(e); throw e; } catch (Error e) { probe.setFailed(e); throw e; } finally { probe.stop(); } } @PreRemove public void preRemove() {
MonitoringProbe probe = Log4jMonitoringProbe.start(getClass().getName(), EntityBL.class.getName() + ".preRemove()"); try { if (getEntityBL() != null) { getEntityBL().onRemove(); } onRemoveImpl(); } catch (RuntimeException e) { probe.setFailed(e); throw e; } catch (Error e) { probe.setFailed(e); throw e; } finally { probe.stop(); } } public void onRemoveImpl() { } public EntityBL getEntityBL() { return ivEntityBL; }
public String getId() { return Id; }
public void setId(String aId) { Id = aId; }
public int getLock_Version() { return Lock_Version; }
public void setLock_Version(int aLock_Version) { Lock_Version = aLock_Version; }
public void checkStaleness(EntityPK aEntityPK) throws OptimisticLockException { if (!this.getId().equals(((EntityPKImpl) aEntityPK).getId())) { throw new IllegalArgumentException("Id of Entity differs from given Id of EntityPK"); }
if (!(this.getLock_Version() == ((EntityPKImpl) aEntityPK).getLock_Version())) { throw new OptimisticLockException("Lock_Version of Entity differs from Lock_Version of EntityPK", null, this); } }
public AMPersistenceContext getPersistenceContext() { return PersistenceContextHolder.getPersistenceContext(); }
/** * The modification user for the current thread * * @return the uset string */ protected String getModificationUser() { return (String) Logger.getVariable(ModificationInfo.USER); }
/** * The modification timestamp * * @return the modification timestamp */ protected Timestamp getModificationTimestamp() { return ((AMEntityManager)getPersistenceContext().getEntityManager()).getModificationTimestamp(); } /** * Checks a string for not being empty with regard to * Oracle, where empty strings are converted to null. * * @param aString the string */ protected void checkStringForEmptyness(String aString) { if ( aString != null && aString.length() == 0) { throw new IllegalArgumentException("Persisted string is empty.\nValid String must be 'null' or not empty!"); } } /** * Returns the implementation for a given entity reference. * If the given object is a proxy, the target object of the proxy will be * returned, otherwise the object itself. * @param <T> the entity type * @param entity the entity reference * @return the entity implementation */ public static <T> T getImpl(T entity) { return EntityUtil.getImpl(entity); } {code} {code} public abstract class CLEntityImpl extends EntityImpl {
public CLEntityImpl(int aParam) { super(aParam); }
/** * Set the non null client id of the entity. * * @param aClientId the id of the client */ public abstract void setClientId(String aClientId); /** * Get the client id of the entity * * @return the client id */ public abstract String getClientId(); } {code} {code} /** * Gruppe entity instance implementation. */ @Audited @Entity(name="Gruppe") @IdClass(_GruppeId.class) @FilterDef(name="ClientIdFilter", parameters={ @ParamDef( name="ClientId", type="string" ) } ) @Filter(name="ClientIdFilter", condition="CLIENTID = :ClientId") @Table(name="GRUPPE", indexes = { }) @Proxy(lazy=true, proxyClass=_GruppeProxy.class) @SuppressWarnings("all") public class _GruppeImpl extends CLEntityImpl implements _GruppeProxy {
/** * client to which the entity belongs */ @Column(name = "CLIENTID") private String ClientId;
@Basic @Column(name="NAME") private String ivName;
public _GruppeImpl() {
this(0); createEntityBL(); }
//only another constructor protected _GruppeImpl(int aParam) {
super(aParam);
}
public EntityPK getPK () {
_GruppePKImpl gruppePKImpl = new _GruppePKImpl(); gruppePKImpl.setId(getId()); gruppePKImpl.setClientId(getClientId()); gruppePKImpl.setLock_Version(getLock_Version()); return gruppePKImpl; }
@Override public boolean equals(Object o) { return ((o instanceof Gruppe) && getPK().equals(((Gruppe)o).getPK())); } @Override public int hashCode() {
return getPK().hashCode(); } /** * getter for Client. */ public String getClientId() {
return ClientId; }
/** * setter for Client. */ public void setClientId(String aClientId) {
ClientId = aClientId; } @Override public String getName() { return ivName; } @Override public void setName(String aName) { checkStringForEmptyness(aName); ivName = aName; } {code} When trying to audit a relation to another entity with envers, Hibernate's BasicBinder class fails with a ClassCastException on trying to set Id-Class instance to ClientId/Id-values, when trying to persist to the audit table.
After spending a few hours of work, I found out, that in class org.hibernate.envers.internal.entities.mapper.id.SingleIdMapper.mapToMapFromEntity(...) {code} @Override public void mapToMapFromEntity(Map<String, Object> data, Object obj) { if ( obj == null ) { data.put( propertyData.getName(), null ); } else { if ( obj instanceof HibernateProxy ) { final HibernateProxy hibernateProxy = (HibernateProxy) obj; data.put( propertyData.getName(), hibernateProxy.getHibernateLazyInitializer().getIdentifier() ); } else { final Getter getter = ReflectionTools.getGetter( obj.getClass(), propertyData ); data.put( propertyData.getName(), getter.get( obj ) ); } } } {code} properties of the Id-Class are not extracted, when having a proxy. This seems to be a bug , . |
|