DATACMNS-1735 - Fix ConcurrencyModificationException in EntityCallbackDiscoverer.

We now guard modifications of the cached entity callbacks list with a synchronization block.

Original pull request: #446.
This commit is contained in:
mhyeon-lee
2020-05-27 15:10:25 +09:00
committed by Mark Paluch
parent ce7928b28b
commit d9969cb7d4
2 changed files with 46 additions and 3 deletions

View File

@@ -18,6 +18,9 @@ package org.springframework.data.mapping.callback;
import static org.assertj.core.api.Assertions.*;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
@@ -33,6 +36,7 @@ import org.springframework.data.mapping.PersonDocument;
/**
* @author Christoph Strobl
* @author Myeonghyeon Lee
*/
class EntityCallbackDiscovererUnitTests {
@@ -49,6 +53,40 @@ class EntityCallbackDiscovererUnitTests {
assertThat(entityCallbacks).hasSize(1).element(0).isInstanceOf(MyBeforeSaveCallback.class);
}
@Test // DATACMNS-1735
void shouldDiscoverCallbackTypeConcurrencyCache() throws InterruptedException {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MyConfig.class);
EntityCallbackDiscoverer discoverer = new EntityCallbackDiscoverer(ctx);
int concurrencyCount = 4000;
CountDownLatch startLatch = new CountDownLatch(concurrencyCount);
CountDownLatch doneLatch = new CountDownLatch(concurrencyCount);
List<Exception> exceptions = new CopyOnWriteArrayList<>();
for (int i = 0; i < concurrencyCount; i++) {
Thread thread = new Thread(() -> {
try {
startLatch.countDown();
startLatch.await();
discoverer.getEntityCallbacks(PersonDocument.class,
ResolvableType.forType(BeforeSaveCallback.class));
} catch (Exception ex) {
exceptions.add(ex);
} finally {
doneLatch.countDown();
}
});
thread.start();
}
doneLatch.await();
assertThat(exceptions).isEmpty();
}
@Test // DATACMNS-1467
void shouldDiscoverCallbackTypeByName() {