1

I am writing some tests for a persistance layer I've been working on and I've ran into an exception that that I'm having trouble dealing with, a ConcurrentModificationException it's happening at org.hibernate.mapping.Table.cleanseUniqueKeyMap(Table.java:291).
Which turns out to be this line of code:

final Map.Entry<String,UniqueKey> uniqueKeyEntry = uniqueKeyEntries.next();

After doing a little research I've found out that the exception is caused by one thread modifying this collection while this thread is iterating over it. That being said I feel like there's nothing that I'm doing that's causing this to happen any suggestions on troubleshooting?

BTW, Im using hibernate 4.1.5. Idk if that clears anything up or not. Here's my test:

@Test
public void testCreateMobsterUser() {
   try {            
       final MobsterUserDAO test = new MobsterUserDAO(); //throws exception
       //does stuff w/ return value...

As you can see we try and initialize the dao Let's see that code:

public MobsterUserDAO() {
    super(MobsterUser.class);
}

Well that didn't show us much so let's look at the generic dao constructor and see if you see the problem there.

public MobsterBaseHibernateDAO(final Class<T> clazz) {
    this.clazz = clazz;
    //This next line is where the exception is actually occuring
    final EntityManagerFactory factory = Persistence.createEntityManagerFactory("mobsterdb");
    this.manager = (HibernateEntityManager) factory.createEntityManager();
}

Now I'm not sure what kind of rabbit hole Persistance.createEntityManagerFactory is, but that is the last line of my code that gets executed before the exception occurs.

Andy McCall
  • 446
  • 1
  • 4
  • 15

3 Answers3

3

Concurrent modification happens when you iterate a collection in the for-each loop, and alter the collection somewhere else. One of the common solution is to use Iterator instead of for-each loop. Or have your Collection in synchronized block.

There are resources all over about it:

Avoiding ConcurrentModificationException, It says:

  1. You can convert the list to an array and then iterate on the array. This approach works well for small or medium size list but if the list is large then it will affect the performance a lot.

  2. You can lock the list while iterating by putting it in a synchronized block. This approach is not recommended because it will cease the benefits of multithreading.

  3. If you are using JDK1.5 or higher then you can use ConcurrentHashMap and CopyOnWriteArrayList classes. It is the recommended approach.

Also:

Concurrent Modification exception
How to debug ConcurrentModificationException?

Community
  • 1
  • 1
Nishant
  • 54,584
  • 13
  • 112
  • 127
  • 2
    I get that, but I want to iterate on the point that the exception is occurring within hibernate i.e. not code Ive written. I don't even have multiple threads in my application (at least not by my doing). It has to be caused by the way hibernate is configured that's all I really know. If I posted the printed stack trace would that help. – Andy McCall Jul 18 '12 at 05:12
  • they are not even the same exception. – zinking Apr 28 '15 at 08:47
2

Since it seems like a exception during internal housekeeping by Hibernate, I had assumed that its a bug. A quick search on Google does show a recently reported JIRA.

There is a resolution proposed but no idea when it will be released.

Hope this helps!

akhilss
  • 136
  • 5
  • I appreciate that. That stack trace on the JIRA looks almost identical to mine. – Andy McCall Jul 18 '12 at 06:44
  • So as far as my problem... I should download the source change the map to a concurrent map and recompile? – Andy McCall Jul 18 '12 at 06:55
  • I'd prefer someone try the solution stated in https://hibernate.onjira.com/browse/HHH-7456 But yep, grab the source, make that change and build. Its not as easy as just compiling as we use a few code generation tools in the Hibernate build, just follow the instructions in the readme – Steve Ebersole Jul 18 '12 at 14:46
  • Conversely, if you added a *simplified* test case to the Jira that would work as well... – Steve Ebersole Jul 18 '12 at 14:52
  • @SteveEbersole What would I need to provide? Entity implementation(As a private class), the DAO(another private), and my persistence.xml file? Would that be sufficient or excessive? – Andy McCall Jul 18 '12 at 20:16
  • Well ideally a test case, as in a junit test, that illustrates the failure. And whatever bare minimum is needed along with that to demonstrate the problem – Steve Ebersole Jul 18 '12 at 20:26
0

This happens because you have your loop going through a collection, then somewhere inside the loop, you change the collection you are iterating through, and you try to resume the loop as though nothing has changed.

I have had the same thing happen to me :

for(UserJPA jpa : jpaList){
    if(jpa satisfies a condition){
        jpaList.remove(jpa);
    }
}

The problem is that you can't modify the list you are iterating through. The solution i opted for in my case was to make a new list, a copy of the original, to iterate through it, while modifying the original list :

List<UserJPA> iterationList = new ArrayList<UserJPA>(jpaList);
for(UserJPA jpa : iterationList){
    if(jpa satisfies a condition){
        jpaList.remove(jpa);
    }
}

Hope that helps.

Lazaruss
  • 1,107
  • 1
  • 13
  • 24