1

In my application, I have a several audited entity classes for example the following.
It contains multiple HAS-IS relations to other entities with various hibernate annotations.

@Entity
@Audited
public class Entity implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    private Integer Id;

    @ManyToMany
    private Set < Country> affectedCountries;

    @OneToOne
    private Impact impact;

    @Enumerated(EnumType.STRING)
    private Owner owner;

    ...
}

I am analyzing the the audit-trail with the following code snipplet, which return all the attribute values from the audit table entity.

public List< AuditTrailForm> getAuditTrailEntries(Class< ?> clazz, Serializable id) {
        AuditReader reader = AuditReaderFactory.get(this.getSession());
        List < Number> revNumbers = reader.getRevisions(clazz, id);
        List< AuditTrailForm> forms = new ArrayList();
        Iterator< Number> it = revNumbers.iterator();

        while(it.hasNext()) {

            Number item = it.next();
            Object obj = reader.find(clazz, id, item);
            AuditInfo revision = reader.findRevision(AuditInfo.class, item);

            BeanMap beanMap = new BeanMap(obj);
            HashMap map = new HashMap();

            Set keys = beanMap.keySet( );
            Iterator keyIterator = keys.iterator( );

            while( keyIterator.hasNext( ) ) {
               String propertyName = (String) keyIterator.next( );

                if (beanMap.getType(propertyName).equals(String.class)) {
                   String propertyValue = (String) beanMap.get( propertyName );
                      map.put(propertyName, propertyValue);  
                }
            }   
            Date createdAt = revision.getTimestamp();
            String user = revision.getUser();

            AuditTrailForm form = new AuditTrailForm(user, createdAt, map);
            forms.add(form);
        }
        return forms;
}

Works fine, however this doesn't take into account the traversing the relations in the class.
Could I somehow develop a recursive algorithm, which would detect the type of the object attribute and then do the recursive call?
Is there perhaps a better way to do this altogether?

3
  • 1
    I understand the auditing, but I'm a bit puzzled about the purpose of the beanMap and why you extract string valued properties. Can you explain what you want to achieve? Commented Jul 22, 2010 at 22:40
  • Ultimate I want to have a map of "date, user, old value, new value" of the parent and child entities. The problem is that, if I have hibernate relationship C -> <SET>B and somebody changes something in the B entity and new revision of created out of the C entity, but I don't have any means of traversing to the B entity from the C revision. Commented Jul 23, 2010 at 13:58
  • If I understood you comment right: you need to set up cascade update like: @ManyToMany(cascade=CascadeType.ALL) and do to reload object C from DB in your code's spot. Commented Jun 22, 2022 at 11:00

1 Answer 1

2

A simpler approach...

I'm assuming that the saves to the object tree happen in a transaction. You could modify the audit tables to also add some unique identifier for each transaction.

That way you would be able to browse the audit history as a collection of change sets - e.g. see all changes made in a single transaction.

Not quite what you are asking for but would be a lot easier to achieve and give many of the benefits. What you are asking for would be very complicated to implement.

Sign up to request clarification or add additional context in comments.

1 Comment

I implemented a messy solution using the code.google.com/p/reflections library to detect the auditable objects and iterating through the collection. It fulfills the requirement at the moment, before the new version of Envers is released.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.