1

I have extended the EmptyInterceptor provided by hibernate to perform some logic on post flush. The overwritten post flush method is provided with an iterator. When I tried to iterate, I received ConcurrentModificationException.

Below is my code snippet,

@Override
public void postFlush(Iterator entities) throws CallbackException
{
    while (entities.hasNext())
    {
        Object entity;

        try
        {
            entity = entities.next();
        }
        catch(ConcurrentModificationException e)
        {
            // I get concurrent modification exception while iterating.

            return;
        }

    }
}

I am getting the below exception,

java.util.ConcurrentModificationException at java.util.HashMap$HashIterator.nextEntry(HashMap.java:922) at java.util.HashMap$ValueIterator.next(HashMap.java:950) at org.hibernate.internal.util.collections.LazyIterator.next(LazyIterator.java:51) at com.mycompany.MyInterceptor.postFlush(MyInterceptor.java:55) at org.hibernate.event.internal.AbstractFlushingEventListener.postPostFlush(AbstractFlushingEventListener.java:401) at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:70) at org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1130) at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1580) at org.hibernate.internal.CriteriaImpl.list(CriteriaImpl.java:374)

From Hibernate Forum we can understand that the iterator passed to the postFlush() method is not thread safe causing ConcurrentModificationException.

Suggestions and solution to avoid the exception is appreciated.

4 Answers4

0

If it's synchronization issue try using a ConcurrentHashMap instead of a plain HashMap

See also this answer i think it might help

Community
  • 1
  • 1
karim mohsen
  • 2,164
  • 1
  • 15
  • 19
0

Manually copy it in a List

    @Override
        public void postFlush(Iterator entities) {
            super.postFlush(entities);
            List<Object> objects = new ArrayList<>();
            while (entities.hasNext()) {
                objects.add(entities.next());
            }
.
.
.

now you can use objects list

Nik Kashi
  • 4,447
  • 3
  • 40
  • 63
0

If you look at the implementation of IteratorUtils.toList, it just does:

    List list = new ArrayList(estimatedSize);
    while (iterator.hasNext()) {
        list.add(iterator.next());
    }

which isn't any faster than doing it that way, except... perhaps by allocating the list with an estimated size of 10, it is faster because it isn't necessarily having to re-allocate...

-1

Copying iterator into a list via org.apache.commons.collections.IteratorUtils before iterating worked for me :

 @Override
 public void preFlush(Iterator entities) {
    List list= IteratorUtils.toList(entities); 
    for(Object o : list){...}

 }

However i can't explain why it is working when using IteratorUtils...

NzoP
  • 24
  • 2
  • It is a good idea. Did you used this approach to solve the same problem? or is it a common approach that you are proposing? Because this seems to be an issue with the hibernate. – Stanley Paul Sep 03 '15 at 10:39
  • Yes I used it to solve the same problem. After reflection i think that this 'trick' is working because IteratorUtils traverses the Iteraror fast enough to avoid a concurrent modification while traversing it. But it might still occur I think, so i would advise to catch the ConcurrentModificationException and retry to copy it until it works... not very sexy though...Or maybe apache internally handles ConcurrentModificationException. I agree that this is a hibernate issue. – NzoP Sep 04 '15 at 08:45
  • I checked apache IteratorUtils.toList code and it does not handle ConcurrentModificationException. – NzoP Sep 04 '15 at 08:53
  • Thanks!! It worked for me. As you said it is still a mystery why Apache util don't throws concurrent modification exception. – Stanley Paul Sep 04 '15 at 09:35