Use ConcurrentMap declarations when calling putIfAbsent (for compatibility with JDK 6 and 7)

Issue: SPR-12102
This commit is contained in:
Juergen Hoeller 2014-08-19 23:28:42 +02:00
parent 781a6d289e
commit af6ef5f74c
2 changed files with 16 additions and 11 deletions

View File

@ -480,8 +480,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
} }
TypeDescriptor td = cachedIntrospectionResults.getTypeDescriptor(pd); TypeDescriptor td = cachedIntrospectionResults.getTypeDescriptor(pd);
if (td == null) { if (td == null) {
td = new TypeDescriptor(property(pd)); td = cachedIntrospectionResults.addTypeDescriptor(pd, new TypeDescriptor(property(pd)));
cachedIntrospectionResults.addTypeDescriptor(pd, td);
} }
return convertForProperty(propertyName, null, value, td); return convertForProperty(propertyName, null, value, td);
} }

View File

@ -27,6 +27,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@ -112,14 +113,14 @@ public class CachedIntrospectionResults {
* Map keyed by Class containing CachedIntrospectionResults, strongly held. * Map keyed by Class containing CachedIntrospectionResults, strongly held.
* This variant is being used for cache-safe bean classes. * This variant is being used for cache-safe bean classes.
*/ */
static final Map<Class<?>, CachedIntrospectionResults> strongClassCache = static final ConcurrentMap<Class<?>, CachedIntrospectionResults> strongClassCache =
new ConcurrentHashMap<Class<?>, CachedIntrospectionResults>(64); new ConcurrentHashMap<Class<?>, CachedIntrospectionResults>(64);
/** /**
* Map keyed by Class containing CachedIntrospectionResults, softly held. * Map keyed by Class containing CachedIntrospectionResults, softly held.
* This variant is being used for non-cache-safe bean classes. * This variant is being used for non-cache-safe bean classes.
*/ */
static final Map<Class<?>, CachedIntrospectionResults> softClassCache = static final ConcurrentMap<Class<?>, CachedIntrospectionResults> softClassCache =
new ConcurrentReferenceHashMap<Class<?>, CachedIntrospectionResults>(64); new ConcurrentReferenceHashMap<Class<?>, CachedIntrospectionResults>(64);
@ -186,17 +187,21 @@ public class CachedIntrospectionResults {
} }
results = new CachedIntrospectionResults(beanClass); results = new CachedIntrospectionResults(beanClass);
ConcurrentMap<Class<?>, CachedIntrospectionResults> classCacheToUse;
if (ClassUtils.isCacheSafe(beanClass, CachedIntrospectionResults.class.getClassLoader()) || if (ClassUtils.isCacheSafe(beanClass, CachedIntrospectionResults.class.getClassLoader()) ||
isClassLoaderAccepted(beanClass.getClassLoader())) { isClassLoaderAccepted(beanClass.getClassLoader())) {
strongClassCache.putIfAbsent(beanClass, results); classCacheToUse = strongClassCache;
} }
else { else {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("Not strongly caching class [" + beanClass.getName() + "] because it is not cache-safe"); logger.debug("Not strongly caching class [" + beanClass.getName() + "] because it is not cache-safe");
} }
softClassCache.putIfAbsent(beanClass, results); classCacheToUse = softClassCache;
} }
return results;
CachedIntrospectionResults existing = classCacheToUse.putIfAbsent(beanClass, results);
return (existing != null ? existing : results);
} }
/** /**
@ -246,7 +251,7 @@ public class CachedIntrospectionResults {
private final Map<String, PropertyDescriptor> propertyDescriptorCache; private final Map<String, PropertyDescriptor> propertyDescriptorCache;
/** TypeDescriptor objects keyed by PropertyDescriptor */ /** TypeDescriptor objects keyed by PropertyDescriptor */
private final Map<PropertyDescriptor, TypeDescriptor> typeDescriptorCache; private final ConcurrentMap<PropertyDescriptor, TypeDescriptor> typeDescriptorCache;
/** /**
@ -295,7 +300,7 @@ public class CachedIntrospectionResults {
"; editor [" + pd.getPropertyEditorClass().getName() + "]" : "")); "; editor [" + pd.getPropertyEditorClass().getName() + "]" : ""));
} }
pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd); pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd);
this.propertyDescriptorCache.putIfAbsent(pd.getName(), pd); this.propertyDescriptorCache.put(pd.getName(), pd);
} }
this.typeDescriptorCache = new ConcurrentHashMap<PropertyDescriptor, TypeDescriptor>(); this.typeDescriptorCache = new ConcurrentHashMap<PropertyDescriptor, TypeDescriptor>();
@ -347,8 +352,9 @@ public class CachedIntrospectionResults {
} }
} }
void addTypeDescriptor(PropertyDescriptor pd, TypeDescriptor td) { TypeDescriptor addTypeDescriptor(PropertyDescriptor pd, TypeDescriptor td) {
this.typeDescriptorCache.putIfAbsent(pd, td); TypeDescriptor existing = this.typeDescriptorCache.putIfAbsent(pd, td);
return (existing != null ? existing : td);
} }
TypeDescriptor getTypeDescriptor(PropertyDescriptor pd) { TypeDescriptor getTypeDescriptor(PropertyDescriptor pd) {