Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to determine Collection changes in a Hibernate PostUpdateEventListener?

Tags:

hibernate

In Hibernate, implementing a PostUpdateEventListener allows you to plug into Hibernate's workflow and gives you the opportunity to inspect and compare the old and new values of an Entity's properties as it is being saved (PostUpdateEvent has methods getOldState() and getState() that return an array of these values). For standard properties, this works just fine. However, where one of those properties is a Collection whose contents have changed, this is of no help: the "old value" and "new value" are both just the same reference to the Collection (since the Collection itself has not changed, just its contents). This means you can only see the latest i.e. "new" contents of that Collection.

Anyone know if there is a way to determine how the elements of a Collection owned by an Entity have changed at this point in the workflow?

like image 226
alasdairg Avatar asked Jan 24 '23 16:01

alasdairg


1 Answers

I figured out a way to do this, so I'll post it in case its of use to anyone else. This code loops through all the "old state" properties, and for any which are persistent collections, obtains the previous contents 'snapshot'. It then wraps this in an unmodifiable collection for good measure:

public void onPostUpdate( PostUpdateEvent event )
{       
   for ( Object item: event.getOldState() )
   {
      Object previousContents = null;

      if ( item != null && item instanceof PersistentCollection )               
      {
         PersistentCollection pc = (PersistentCollection) item;
         PersistenceContext context = session.getPersistenceContext();            
         CollectionEntry entry = context.getCollectionEntry( pc );
         Object snapshot = entry.getSnapshot();

         if ( snapshot == null )
            continue;

         if ( pc instanceof List )
         {
            previousContents = Collections.unmodifiableList( (List) snapshot );
         }        
         else if ( pc instanceof Map )
         {
            previousContents = Collections.unmodifiableMap( (Map) snapshot );
         }
         else if ( pc instanceof Set )
         {  
            //Set snapshot is actually stored as a Map                
            Map snapshotMap = (Map) snapshot;
            previousContents = Collections.unmodifiableSet( new HashSet( snapshotMap.values() ) );          
         }
         else
           previousContents = pc;

      //Do something with previousContents here
  }   
like image 86
alasdairg Avatar answered Jan 26 '23 09:01

alasdairg