This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch GROOVY_5_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/GROOVY_5_0_X by this push:
new e31f89d007 GROOVY-11841: use `ConcurrentHashMap` for mutable property
index maps
e31f89d007 is described below
commit e31f89d007f0dc4c2b2e0cb24872ea1e77cd4cdb
Author: Eric Milles <[email protected]>
AuthorDate: Thu Jan 15 13:30:51 2026 -0600
GROOVY-11841: use `ConcurrentHashMap` for mutable property index maps
5_0_X backport
---
src/main/java/groovy/lang/MetaClassImpl.java | 101 +++++++++++----------------
1 file changed, 39 insertions(+), 62 deletions(-)
diff --git a/src/main/java/groovy/lang/MetaClassImpl.java
b/src/main/java/groovy/lang/MetaClassImpl.java
index 1f90450e74..d2a92cc5b6 100644
--- a/src/main/java/groovy/lang/MetaClassImpl.java
+++ b/src/main/java/groovy/lang/MetaClassImpl.java
@@ -154,13 +154,15 @@ public class MetaClassImpl implements MetaClass,
MutableMetaClass {
protected final boolean isMap;
protected final MetaMethodIndex metaMethodIndex;
- private final Map<CachedClass, LinkedHashMap<String, MetaProperty>>
classPropertyIndex = new LinkedHashMap<>();
+ private static Map<String, MetaProperty> subMap(Map<CachedClass,
Map<String, MetaProperty>> map, CachedClass key) {
+ return map.computeIfAbsent(key, k -> new LinkedHashMap<>());
+ }
+ private final Map<CachedClass, Map<String, MetaProperty>>
classPropertyIndexForSuper = new ConcurrentHashMap<>();
+ private final Map<CachedClass, Map<String, MetaProperty>>
classPropertyIndex = new ConcurrentHashMap<>();
private final Map<String, MetaProperty> staticPropertyIndex = new
LinkedHashMap<>();
+
private final Map<String, MetaMethod> listeners = new LinkedHashMap<>();
private final List<MetaMethod> allMethods = new ArrayList<>();
- // we only need one of these that can be reused over and over.
- private final MetaProperty arrayLengthProperty = new
MetaArrayLengthProperty();
- private final Map<CachedClass, LinkedHashMap<String, MetaProperty>>
classPropertyIndexForSuper = new LinkedHashMap<>();
private final Set<MetaMethod> newGroovyMethodsSet = new LinkedHashSet<>();
private final MetaMethod[] myNewMetaMethods;
private final MetaMethod[] additionalMetaMethods;
@@ -291,12 +293,12 @@ public class MetaClassImpl implements MetaClass,
MutableMetaClass {
public MetaProperty getMetaProperty(final String name) {
MetaProperty metaProperty = null;
- LinkedHashMap<String, MetaProperty> propertyMap =
classPropertyIndex.computeIfAbsent(theCachedClass, k -> new LinkedHashMap<>());
+ Map<String, MetaProperty> propertyMap = subMap(classPropertyIndex,
theCachedClass);
metaProperty = propertyMap.get(name);
if (metaProperty == null) {
metaProperty = staticPropertyIndex.get(name);
if (metaProperty == null) {
- propertyMap =
classPropertyIndexForSuper.computeIfAbsent(theCachedClass, k -> new
LinkedHashMap<>());
+ propertyMap = subMap(classPropertyIndexForSuper,
theCachedClass);
metaProperty = propertyMap.get(name);
if (metaProperty == null) {
MetaBeanProperty property =
findPropertyInClassHierarchy(name, theCachedClass);
@@ -1287,7 +1289,10 @@ public class MetaClassImpl implements MetaClass,
MutableMetaClass {
* Tries to find a callable property and make the call.
*/
private Object invokePropertyOrMissing(final Object object, final String
methodName, final Object[] originalArguments, final boolean fromInsideClass,
final boolean isCallToSuper) {
- MetaProperty metaProperty = this.getMetaProperty(methodName, false);
+ MetaProperty metaProperty = null;
+
+ Map<String, MetaProperty> propertyMap =
classPropertyIndex.get(theCachedClass);
+ if (propertyMap != null) metaProperty = propertyMap.get(methodName);
Object value = null;
if (metaProperty != null) {
@@ -2329,23 +2334,17 @@ public class MetaClassImpl implements MetaClass,
MutableMetaClass {
}
/**
- * This will build up the property map (Map of MetaProperty objects, keyed
on
- * property name).
+ * Populates the map of MetaProperty objects, keyed by class and property
name.
*
* @param propertyDescriptors the property descriptors
*/
private void setUpProperties(final PropertyDescriptor[]
propertyDescriptors) {
if (theCachedClass.isInterface) {
- for (CachedClass iface : theCachedClass.getInterfaces()) { //
includes theCachedClass
- classPropertyIndex.computeIfAbsent(iface, x -> {
- var index = new LinkedHashMap<String, MetaProperty>();
- addConsts(iface, index);
- return index;
- });
- }
+ addConsts(theCachedClass, subMap(classPropertyIndex,
theCachedClass));
+
applyPropertyDescriptors(propertyDescriptors);
CachedClass superClass = ReflectionCache.OBJECT_CLASS;
- applyStrayPropertyMethods(superClass,
classPropertyIndex.computeIfAbsent(superClass, x -> new LinkedHashMap<>()),
true);
+ applyStrayPropertyMethods(superClass, subMap(classPropertyIndex,
superClass), true);
} else {
List<CachedClass> superClasses = getSuperClasses();
List<CachedClass> superInterfaces = new
ArrayList<>(theCachedClass.getInterfaces());
@@ -2356,9 +2355,7 @@ public class MetaClassImpl implements MetaClass,
MutableMetaClass {
}
if (theCachedClass.isArray) { // add the special read-only
"length" property
- var map = new LinkedHashMap<String, MetaProperty>();
- map.put("length", arrayLengthProperty);
- classPropertyIndex.put(theCachedClass, map);
+ subMap(classPropertyIndex, theCachedClass).put("length", new
MetaArrayLengthProperty());
}
inheritStaticInterfaceFields(superClasses, superInterfaces);
@@ -2390,7 +2387,7 @@ public class MetaClassImpl implements MetaClass,
MutableMetaClass {
}
};
- classPropertyIndex.computeIfAbsent(theCachedClass, x -> new
LinkedHashMap<>()).forEach(indexStaticProperty);
+ subMap(classPropertyIndex,
theCachedClass).forEach(indexStaticProperty);
if (theCachedClass.isInterface) { // GROOVY-10592: static interface
accessors
Map<String, MetaProperty> strayProperties = new LinkedHashMap<>();
@@ -2457,14 +2454,14 @@ public class MetaClassImpl implements MetaClass,
MutableMetaClass {
private void inheritStaticInterfaceFields(List<CachedClass> superClasses,
Iterable<CachedClass> interfaces) {
for (CachedClass iface : interfaces) {
- LinkedHashMap<String, MetaProperty> iPropertyIndex =
classPropertyIndex.computeIfAbsent(iface, x -> {
+ Map<String, MetaProperty> iPropertyIndex =
classPropertyIndex.computeIfAbsent(iface, x -> {
var index = new LinkedHashMap<String, MetaProperty>();
addConsts(iface, index);
return index;
});
for (CachedClass superClass : superClasses) {
if
(!iface.getTheClass().isAssignableFrom(superClass.getTheClass())) continue;
- LinkedHashMap<String, MetaProperty> sPropertyIndex =
classPropertyIndex.computeIfAbsent(superClass, x -> new LinkedHashMap<>());
+ Map<String, MetaProperty> sPropertyIndex =
subMap(classPropertyIndex, superClass);
copyNonPrivateFields(iPropertyIndex, sPropertyIndex, null);
}
}
@@ -2473,11 +2470,11 @@ public class MetaClassImpl implements MetaClass,
MutableMetaClass {
private void inheritFields(final Iterable<CachedClass> superClasses) {
Map<String, MetaProperty> sci = null;
for (CachedClass cc : superClasses) {
- Map<String, MetaProperty> cci =
classPropertyIndex.computeIfAbsent(cc, x -> new LinkedHashMap<>());
+ Map<String, MetaProperty> cci = subMap(classPropertyIndex, cc);
if (sci != null && !sci.isEmpty()) {
copyNonPrivateFields(sci, cci, cc);
// GROOVY-9608, GROOVY-9609: add public, protected, and
package-private fields to index for super
- copyNonPrivateFields(sci,
classPropertyIndexForSuper.computeIfAbsent(cc, x -> new LinkedHashMap<>()), cc);
+ copyNonPrivateFields(sci, subMap(classPropertyIndexForSuper,
cc), cc);
}
sci = cci;
addFields(cc, cci);
@@ -2507,9 +2504,9 @@ public class MetaClassImpl implements MetaClass,
MutableMetaClass {
}
}
- private void applyStrayPropertyMethods(Iterable<CachedClass> classes,
Map<CachedClass, LinkedHashMap<String, MetaProperty>> propertyIndex, boolean
isThis) {
+ private void applyStrayPropertyMethods(Iterable<CachedClass> classes,
Map<CachedClass, Map<String, MetaProperty>> propertyIndex, boolean isThis) {
for (CachedClass cc : classes) {
- applyStrayPropertyMethods(cc, propertyIndex.computeIfAbsent(cc, x
-> new LinkedHashMap<>()), isThis);
+ applyStrayPropertyMethods(cc, subMap(propertyIndex, cc), isThis);
}
}
@@ -2649,7 +2646,7 @@ public class MetaClassImpl implements MetaClass,
MutableMetaClass {
if (staticProperty != null) {
staticPropertyIndex.put(mp.getName(), mp);
} else {
- Map<String, MetaProperty> propertyMap =
classPropertyIndex.computeIfAbsent(theCachedClass, k -> new LinkedHashMap<>());
+ Map<String, MetaProperty> propertyMap = subMap(classPropertyIndex,
theCachedClass);
// remember field
CachedField field;
MetaProperty old = propertyMap.get(mp.getName());
@@ -2695,7 +2692,7 @@ public class MetaClassImpl implements MetaClass,
MutableMetaClass {
boolean isStatic = (theClass != Class.class && object instanceof
Class);
if (isStatic && object != theClass) {
MetaClass mc = registry.getMetaClass((Class<?>) object);
- mc.getProperty(sender, object, name, useSuper, fromInsideClass);
+ mc.setProperty(sender, object, name, newValue, useSuper,
fromInsideClass);
return;
}
@@ -2779,7 +2776,7 @@ public class MetaClassImpl implements MetaClass,
MutableMetaClass {
//----------------------------------------------------------------------
// generic set method
//----------------------------------------------------------------------
- // check for a generic get method provided through a category
+ // check for a generic set method provided through a category
if (method == null && !useSuper && !isStatic &&
GroovyCategorySupport.hasCategoryInCurrentThread()) {
method = getCategoryMethodSetter(theClass, "set", true);
if (method != null) arguments = new Object[]{name, newValue};
@@ -2834,44 +2831,25 @@ public class MetaClassImpl implements MetaClass,
MutableMetaClass {
}
}
- private MetaProperty getMetaProperty(final Class clazz, final String name,
final boolean useSuper, final boolean useStatic) {
- if (clazz == theClass && !useSuper)
- return getMetaProperty(name, useStatic);
-
- CachedClass cachedClass = ReflectionCache.getCachedClass(clazz);
- while (true) {
- Map<String, MetaProperty> propertyMap;
- if (useStatic) {
- propertyMap = staticPropertyIndex;
- } else if (useSuper) {
- propertyMap = classPropertyIndexForSuper.get(cachedClass);
- } else {
- propertyMap = classPropertyIndex.get(cachedClass);
- }
- if (propertyMap == null) {
- if (cachedClass != theCachedClass) {
- cachedClass = theCachedClass;
- continue;
- } else {
- return null;
- }
- }
- return propertyMap.get(name);
- }
- }
+ private MetaProperty getMetaProperty(final Class<?> clazz, final String
name, final boolean useSuper, final boolean useStatic) {
+ CachedClass cachedClass = (clazz == theClass ? theCachedClass :
ReflectionCache.getCachedClass(clazz));
- private MetaProperty getMetaProperty(final String name, final boolean
useStatic) {
- CachedClass clazz = theCachedClass;
Map<String, MetaProperty> propertyMap;
if (useStatic) {
propertyMap = staticPropertyIndex;
+ } else if (!useSuper) {
+ propertyMap = classPropertyIndex.get(cachedClass);
} else {
- propertyMap = classPropertyIndex.get(clazz);
+ propertyMap = classPropertyIndexForSuper.get(cachedClass);
}
- if (propertyMap == null) {
+
+ if (propertyMap != null) {
+ return propertyMap.get(name);
+ } else if (cachedClass != theCachedClass) {
+ return getMetaProperty(theClass, name, useSuper, useStatic);
+ } else {
return null;
}
- return propertyMap.get(name);
}
/**
@@ -3410,7 +3388,7 @@ public class MetaClassImpl implements MetaClass,
MutableMetaClass {
Set<String> componentNames = new
HashSet<>(plugin.getRecordComponentNames(theClass));
if (!componentNames.isEmpty()) {
MethodDescriptor[] methodDescriptors = info.getMethodDescriptors();
- Map<String, MetaProperty> propIndex =
classPropertyIndex.computeIfAbsent(theCachedClass, x -> new LinkedHashMap<>());
+ Map<String, MetaProperty> propIndex = subMap(classPropertyIndex,
theCachedClass);
for (MethodDescriptor md : methodDescriptors) {
if (md.getMethod().getParameterCount() != 0) continue;
String name = md.getName();
@@ -3630,7 +3608,6 @@ public class MetaClassImpl implements MetaClass,
MutableMetaClass {
property = searchInterfacesForMetaProperty(propertyName,
superInterfaces);
if (property != null) break;
}
-
}
return property;
}