From 7210a5c2556dab251b93ff782eec7e4e7713e28b Mon Sep 17 00:00:00 2001 From: Thomas Darimont Date: Thu, 30 Oct 2014 09:39:24 +0100 Subject: [PATCH] DATAJPA-620 - Avoid potential infinite loop in CrudMethodMetadataPostProcessor. We now use a ConcurrentHashMap for the metadata cache. Previously we just used an plain HashMap in a potential concurrent read / write situation which could lead to an infinite loop on put. Original pull request: #111. --- .../support/CrudMethodMetadataPostProcessor.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/springframework/data/jpa/repository/support/CrudMethodMetadataPostProcessor.java b/src/main/java/org/springframework/data/jpa/repository/support/CrudMethodMetadataPostProcessor.java index 016a6a1d6..b5a31f884 100644 --- a/src/main/java/org/springframework/data/jpa/repository/support/CrudMethodMetadataPostProcessor.java +++ b/src/main/java/org/springframework/data/jpa/repository/support/CrudMethodMetadataPostProcessor.java @@ -19,6 +19,8 @@ import java.lang.reflect.Method; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import javax.persistence.LockModeType; import javax.persistence.QueryHint; @@ -81,12 +83,13 @@ enum CrudMethodMetadataPostProcessor implements RepositoryProxyPostProcessor { * * @see DefaultCrudMethodMetadata * @author Oliver Gierke + * @author Thomas Darimont */ static enum CrudMethodMetadataPopulatingMethodIntercceptor implements MethodInterceptor { INSTANCE; - private final Map metadataCache = new HashMap(); + private final ConcurrentMap metadataCache = new ConcurrentHashMap(); /* * (non-Javadoc) @@ -104,8 +107,13 @@ enum CrudMethodMetadataPostProcessor implements RepositoryProxyPostProcessor { CrudMethodMetadata methodMetadata = metadataCache.get(method); if (methodMetadata == null) { + methodMetadata = new DefaultCrudMethodMetadata(method); - metadataCache.put(method, methodMetadata); + CrudMethodMetadata tmp = metadataCache.putIfAbsent(method, methodMetadata); + + if (tmp != null) { + metadata = tmp; + } } TransactionSynchronizationManager.bindResource(method, methodMetadata);