'Iterator provided by the Hibernate Interceptor post flush method throws ConcurrentModificationException

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.



Solution 1:[1]

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

See also this answer i think it might help

Solution 2:[2]

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

Solution 3:[3]

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...

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Community
Solution 2 Mohsen Kashi
Solution 3 Ken Larson