I have some entities. For example
@Entity @IdClass(SecurityUserPublisherId.class) @Table(name="SECUSERPUB") public class SecurityUserPublisher extends Auditable { private static final long serialVersionUID = 1L; @Id @Column(name="USERPUB_CONTACTID", updatable=false, nullable=false) protected Integer contactId = null; @Id @Column(name="USERPUB_PUBID", updatable=false, nullable=false) protected Integer publisherId = null; public SecurityUserPublisher() { super(); setAudited(true); } public SecurityUserPublisher(SecurityUserPublisher securityUserPublisher) { setContactId(securityUserPublisher.getContactId()); setPublisherId(securityUserPublisher.getPublisherId()); } public Integer getContactId() {return contactId;} public void setContactId(Integer contactId) {this.contactId = contactId;} public Integer getPublisherId() {return publisherId;} public void setPublisherId(Integer publisherId) {this.publisherId = publisherId;} @Transient @Override public String getPrimaryKeyDisplay() { StringBuilder sb = new StringBuilder(); if (contactId == null) { sb.append(" contactId: null"); } else { sb.append(" contactId: " + contactId.toString()); } if (publisherId == null) { sb.append(" publisherId: null"); } else { sb.append(" publisherId: " + publisherId.toString()); } return sb.toString(); } @Transient @Override public String getAuditDetail() { return new ToStringBuilder(this).append("contactId", contactId).append("publisherId", publisherId).toString(); } }
They extend the Auditable class
public abstract class Auditable implements Serializable { private static final long serialVersionUID = 1L; protected Integer auditContactId = null; protected Boolean audited = false; public void setAuditContactId(Integer auditContactId) {this.auditContactId = auditContactId;} public Integer getAuditContactId() {return auditContactId;} public Boolean isAudited() {return audited;} protected void setAudited(Boolean audited) {this.audited = audited;} public abstract String getPrimaryKeyDisplay(); public abstract String getAuditDetail(); }
And I have an interceptor
public class AuditInterceptor extends EmptyInterceptor { private static final long serialVersionUID = 1L; private Set<Auditable> inserts = new HashSet<>(); private Set<Auditable> updates = new HashSet<>(); private Set<Auditable> deletes = new HashSet<>(); @Override public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) throws CallbackException { if (entity != null && entity instanceof Auditable && ((Auditable)entity).isAudited()){ System.out.println(entity.toString()); System.out.println(id.toString()); System.out.println(Arrays.toString(state)); System.out.println(Arrays.toString(propertyNames)); System.out.println(Arrays.toString(types)); inserts.add((Auditable)entity); } return super.onSave(entity, id, state, propertyNames, types); } @Override public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) throws CallbackException { if (entity instanceof Auditable && ((Auditable)entity).isAudited()){ updates.add((Auditable)entity); } return super.onFlushDirty(entity, id, currentState, previousState, propertyNames, types); } @Override public void onDelete(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) { if (entity instanceof Auditable && ((Auditable)entity).isAudited()){ System.out.println(entity.toString()); System.out.println(id.toString()); System.out.println(Arrays.toString(state)); System.out.println(Arrays.toString(propertyNames)); System.out.println(Arrays.toString(types)); deletes.add((Auditable)entity); } } //called before commit into database @Override public void preFlush(@SuppressWarnings("rawtypes") Iterator iterator) { } //called after committed into database @Override public void postFlush(@SuppressWarnings("rawtypes") Iterator iterator) { try { for (Iterator<Auditable> iter = inserts.iterator(); iter.hasNext();) { Auditable entity = iter.next(); iter.remove(); logIt("Saved", entity); } for (Iterator<Auditable> iter = updates.iterator(); iter.hasNext();) { Auditable entity = iter.next(); iter.remove(); logIt("Updated", entity); } for (Iterator<Auditable> iter = deletes.iterator(); iter.hasNext();) { Auditable entity = iter.next(); iter.remove(); logIt("Deleted", entity); } } finally { inserts.clear(); updates.clear(); deletes.clear(); } } public void logIt(String action, Auditable entity) { if (!entity.isAudited()) { return; } Session tempSession = SessionHelper.getSession().getSession().getSessionFactory().openSession(); Audit auditRecord = new Audit(); auditRecord.setAction(action); auditRecord.setContactId(entity.getAuditContactId()); auditRecord.setDetail(entity.getAuditDetail()); auditRecord.setCreatedTimestamp(new Timestamp(System.currentTimeMillis())); auditRecord.setEntityPK(entity.getPrimaryKeyDisplay()); auditRecord.setEntityName(entity.getClass().toString()); tempSession.save(auditRecord); tempSession.flush(); } }
I can create entities
final SecurityUserPublisher secUserPub = new SecurityUserPublisher(); secUserPub.setContactId(currentUser.getContactId()); secUserPub.setPublisherId(publisher.getId()); secUserPub.setAuditContactId(parentFrame.getUser().getContactId()); try { SessionHelper.getCreate().createSecurityUserPublisher(secUserPub);
and the audit trail looks good
AUDIT_ID 120385
AUDIT_ACTION Saved
AUDIT_DETAIL SecurityUserPublisher@678541a[contactId=8721,publisherId=360] AUDIT_CREATEDTS 2019-04-04 13:52:57
AUDIT_ENTITYPK contactId: 8721 publisherId: 360
AUDIT_ENTITYNAME SecurityUserPublisher
AUDIT_CONTACTID 7341
But when I try to delete
final SecurityUserPublisher secUserPub = SessionHelper.getSession().getSecurityUserPublisher(currentUser.getContactId(), publisher.getId()); secUserPub.setAuditContactId(parentFrame.getUser().getContactId()); try { SessionHelper.getRemove().removeSecurityUserPublisher(secUserPub);
the audit trail contact id is null, even though I expressly set it before calling the remove.
AUDIT_ID 120386
AUDIT_ACTION Deleted
AUDIT_DETAIL SecurityUserPublisher@1d184bc8[contactId=8721,publisherId=360]
AUDIT_CREATEDTS 2019-04-04 13:53:35
AUDIT_ENTITYPK contactId: 8721 publisherId: 360
AUDIT_ENTITYNAME SecurityUserPublisher
AUDIT_CONTACTID null
So, how do I get the onDelete to show the contactId in the Audit table?
Advertisement
Answer
Use @MappedSuperclass annotation on Auditable class. Otherwise Hibernate ignores super class fields and fields of Auditable class are not saved into DB.