You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2020/07/12 15:19:14 UTC

[groovy] branch GROOVY-9631 updated (e8afcef -> 06315d1)

This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a change to branch GROOVY-9631
in repository https://gitbox.apache.org/repos/asf/groovy.git.


 discard e8afcef  GROOVY-9631: Replace legacy data structure with Java collection
     add b388a25  move assets so that they are in the correct place "in situ" to help with viewing adoc files on github or IDE (closes #1305)
     add e927da2  GROOVY-9633: Refresh the doco for the Groovy Console
     add b95baf5  GROOVY-9601: reduce checks made by findClassMember and getPropertyName
     add 6d8ca74  GROOVY-9601: Remove redundant checks
     add 0315bb0  GROOVY-9601: tweak checks
     add ca6683c  GROOVY-9634: use getDeclaredMethods(String), not getMethods(String)
     add 985dcdb  Add a regression test for GROOVY-9601
     add 78091c3  Trivial tweak: reduce method calls of `removeAll`
     add 6d610ba  Trivial tweak: reduce method calls of `charAt`
     add b80fcbb  Trivial tweak: reduce method calls of `charAt` further
     add f7f5fc1  Trivial tweak: simplify checks
     new 06315d1  GROOVY-9631: Replace legacy data structure with Java collection

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (e8afcef)
            \
             N -- N -- N   refs/heads/GROOVY-9631 (06315d1)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 gradle/asciidoctor.gradle                          |   4 +-
 .../apache/groovy/ast/tools/MethodNodeUtils.java   |  43 +++++++------
 .../java/org/codehaus/groovy/ast/ClassNode.java    |  69 ++++++++++-----------
 .../groovy/classgen/VariableScopeVisitor.java      |  21 ++++---
 src/spec/{ => doc}/assets/css/style.css            |   0
 src/spec/{ => doc}/assets/css/view-example.css     |   0
 .../assets/img/ChainOfResponsibilityClasses.gif    | Bin
 src/spec/{ => doc}/assets/img/CompositeClasses.gif | Bin
 .../{ => doc}/assets/img/CompositeComponents.gif   | Bin
 .../{ => doc}/assets/img/GroovyInterceptions.png   | Bin
 src/spec/{ => doc}/assets/img/StrategyClasses.gif  | Bin
 .../{ => doc}/assets/img/TemplateMethodClasses.gif | Bin
 src/spec/{ => doc}/assets/img/a380.jpg             | Bin
 .../{ => doc}/assets/img/additionalmodules.png     | Bin
 src/spec/{ => doc}/assets/img/b797-hoax.jpg        | Bin
 src/spec/{ => doc}/assets/img/catalina.gif         | Bin
 src/spec/{ => doc}/assets/img/fileassociation.png  | Bin
 .../assets/img/jconsole-implicit-export.png        | Bin
 src/spec/{ => doc}/assets/img/jconsole.gif         | Bin
 src/spec/{ => doc}/assets/img/native.jpg           | Bin
 src/spec/{ => doc}/assets/img/oc4jpie.gif          | Bin
 src/spec/{ => doc}/assets/img/outdir.png           | Bin
 src/spec/{ => doc}/assets/img/setup.png            | Bin
 src/spec/{ => doc}/assets/img/usageMessageSpec.png | Bin
 src/spec/{ => doc}/assets/img/variables.jpg        | Bin
 src/spec/{ => doc}/assets/js/jquery-2.1.1.min.js   |   0
 src/spec/{ => doc}/assets/js/view-example.js       |   0
 .../bugs/{Groovy8223.groovy => Groovy9601.groovy}  |  33 +++++-----
 .../src/spec/assets/img/astbrowser.png             | Bin 139859 -> 0 bytes
 .../src/spec/assets/img/gconsole-toolbar.png       | Bin 7163 -> 0 bytes
 .../spec/{ => doc}/assets/img/GroovyConsole.gif    | Bin
 .../spec/doc/assets/img/astbrowser_bytecode.png    | Bin 0 -> 50928 bytes
 .../src/spec/doc/assets/img/astbrowser_source.png  | Bin 0 -> 53233 bytes
 .../src/spec/doc/assets/img/cstbrowser.png         | Bin 0 -> 51174 bytes
 .../{ => doc}/assets/img/gconsole-sc-with-visu.png | Bin
 .../assets/img/gconsole-sc-without-visu.png        | Bin
 .../src/spec/doc/assets/img/gconsole-toolbar.png   | Bin 0 -> 8325 bytes
 .../src/spec/doc/groovy-console.adoc               |  26 ++++++--
 .../spec/{ => doc}/assets/img/SwingBuilder001.gif  | Bin
 39 files changed, 110 insertions(+), 86 deletions(-)
 rename src/spec/{ => doc}/assets/css/style.css (100%)
 rename src/spec/{ => doc}/assets/css/view-example.css (100%)
 rename src/spec/{ => doc}/assets/img/ChainOfResponsibilityClasses.gif (100%)
 rename src/spec/{ => doc}/assets/img/CompositeClasses.gif (100%)
 rename src/spec/{ => doc}/assets/img/CompositeComponents.gif (100%)
 rename src/spec/{ => doc}/assets/img/GroovyInterceptions.png (100%)
 rename src/spec/{ => doc}/assets/img/StrategyClasses.gif (100%)
 rename src/spec/{ => doc}/assets/img/TemplateMethodClasses.gif (100%)
 rename src/spec/{ => doc}/assets/img/a380.jpg (100%)
 rename src/spec/{ => doc}/assets/img/additionalmodules.png (100%)
 rename src/spec/{ => doc}/assets/img/b797-hoax.jpg (100%)
 rename src/spec/{ => doc}/assets/img/catalina.gif (100%)
 rename src/spec/{ => doc}/assets/img/fileassociation.png (100%)
 rename src/spec/{ => doc}/assets/img/jconsole-implicit-export.png (100%)
 rename src/spec/{ => doc}/assets/img/jconsole.gif (100%)
 rename src/spec/{ => doc}/assets/img/native.jpg (100%)
 rename src/spec/{ => doc}/assets/img/oc4jpie.gif (100%)
 rename src/spec/{ => doc}/assets/img/outdir.png (100%)
 rename src/spec/{ => doc}/assets/img/setup.png (100%)
 rename src/spec/{ => doc}/assets/img/usageMessageSpec.png (100%)
 rename src/spec/{ => doc}/assets/img/variables.jpg (100%)
 rename src/spec/{ => doc}/assets/js/jquery-2.1.1.min.js (100%)
 rename src/spec/{ => doc}/assets/js/view-example.js (100%)
 copy src/test/groovy/bugs/{Groovy8223.groovy => Groovy9601.groovy} (59%)
 delete mode 100644 subprojects/groovy-console/src/spec/assets/img/astbrowser.png
 delete mode 100644 subprojects/groovy-console/src/spec/assets/img/gconsole-toolbar.png
 rename subprojects/groovy-console/src/spec/{ => doc}/assets/img/GroovyConsole.gif (100%)
 create mode 100644 subprojects/groovy-console/src/spec/doc/assets/img/astbrowser_bytecode.png
 create mode 100644 subprojects/groovy-console/src/spec/doc/assets/img/astbrowser_source.png
 create mode 100644 subprojects/groovy-console/src/spec/doc/assets/img/cstbrowser.png
 rename subprojects/groovy-console/src/spec/{ => doc}/assets/img/gconsole-sc-with-visu.png (100%)
 rename subprojects/groovy-console/src/spec/{ => doc}/assets/img/gconsole-sc-without-visu.png (100%)
 create mode 100644 subprojects/groovy-console/src/spec/doc/assets/img/gconsole-toolbar.png
 rename subprojects/groovy-swing/src/spec/{ => doc}/assets/img/SwingBuilder001.gif (100%)


[groovy] 01/01: GROOVY-9631: Replace legacy data structure with Java collection

Posted by su...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a commit to branch GROOVY-9631
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 06315d195c8954bbfd72f8c84f0fdec419f18f20
Author: Daniel Sun <su...@apache.org>
AuthorDate: Sun Jul 12 23:06:46 2020 +0800

    GROOVY-9631: Replace legacy data structure with Java collection
---
 src/main/java/groovy/lang/MetaClassImpl.java       | 134 +++++++++---------
 .../java/org/codehaus/groovy/ast/ClassHelper.java  |   4 +-
 .../org/codehaus/groovy/reflection/ClassInfo.java  |   6 +-
 .../reflection/GroovyClassValuePreJava7.java       |   1 +
 .../groovy/reflection/MixinInMetaClass.java        |  19 ++-
 .../groovy/reflection/ReflectionCache.java         |   2 +
 .../groovy/runtime/memoize/MemoizeCache.java       |   2 +-
 .../metaclass/ThreadManagedMetaBeanProperty.java   |  16 +--
 .../groovy/util/AbstractConcurrentMap.java         |   1 +
 .../groovy/util/AbstractConcurrentMapBase.java     |   1 +
 .../codehaus/groovy/util/ComplexKeyHashMap.java    |   1 +
 .../codehaus/groovy/util/ManagedConcurrentMap.java |   1 +
 .../groovy/util/ManagedIdentityConcurrentMap.java  | 149 +++++++++++++++++++++
 .../org/codehaus/groovy/util/SingleKeyHashMap.java |   1 +
 .../org/codehaus/groovy/util/TripleKeyHashMap.java |   1 +
 .../util/ManagedIdentityConcurrentMapTest.groovy   |  60 +++++++++
 .../groovy-json/src/spec/test/json/JsonTest.groovy |   4 +-
 .../test/groovy/groovy/json/JsonOutputTest.groovy  |  28 ++--
 18 files changed, 325 insertions(+), 106 deletions(-)

diff --git a/src/main/java/groovy/lang/MetaClassImpl.java b/src/main/java/groovy/lang/MetaClassImpl.java
index f26af35..c98b923 100644
--- a/src/main/java/groovy/lang/MetaClassImpl.java
+++ b/src/main/java/groovy/lang/MetaClassImpl.java
@@ -99,9 +99,8 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Iterator;
+import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
@@ -147,14 +146,14 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
     protected final boolean isMap;
     protected final MetaMethodIndex metaMethodIndex;
 
-    private final Index classPropertyIndex = new MethodIndex();
-    private final SingleKeyHashMap staticPropertyIndex = new SingleKeyHashMap();
-    private final Map<String, MetaMethod> listeners = new HashMap<>();
+    private final Map<CachedClass, LinkedHashMap<String, MetaProperty>> classPropertyIndex = new LinkedHashMap<>();
+    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 Index classPropertyIndexForSuper = new MethodIndex();
-    private final Set<MetaMethod> newGroovyMethodsSet = new HashSet<>();
+    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;
 
@@ -280,15 +279,15 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
      * @see MetaObjectProtocol#getMetaProperty(String)
      */
     public MetaProperty getMetaProperty(String name) {
-        MetaProperty metaProperty = null;
+        MetaProperty metaProperty;
 
-        SingleKeyHashMap propertyMap = classPropertyIndex.getNotNull(theCachedClass);
-        metaProperty = (MetaProperty) propertyMap.get(name);
+        LinkedHashMap<String, MetaProperty> propertyMap = classPropertyIndex.computeIfAbsent(theCachedClass, k -> new LinkedHashMap<>());
+        metaProperty = propertyMap.get(name);
         if (metaProperty == null) {
-            metaProperty = (MetaProperty) staticPropertyIndex.get(name);
+            metaProperty = staticPropertyIndex.get(name);
             if (metaProperty == null) {
-                propertyMap = classPropertyIndexForSuper.getNotNull(theCachedClass);
-                metaProperty = (MetaProperty) propertyMap.get(name);
+                propertyMap = classPropertyIndexForSuper.computeIfAbsent(theCachedClass, k -> new LinkedHashMap<>());
+                metaProperty = propertyMap.get(name);
                 if (metaProperty == null) {
                     MetaBeanProperty property = findPropertyInClassHierarchy(name, theCachedClass);
                     if (property != null) {
@@ -1623,7 +1622,7 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
         };
         l.sort(comp);
         int found = -1;
-        for (int i = 0; i < l.size(); i++) {
+        for (int i = 0, n = l.size(); i < n; i++) {
             if (l.get(i) != constructor) continue;
             found = i;
             break;
@@ -2174,16 +2173,16 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
      */
     public List<MetaProperty> getProperties() {
         checkInitalised();
-        SingleKeyHashMap propertyMap = classPropertyIndex.getNullable(theCachedClass);
+        LinkedHashMap<String, MetaProperty> propertyMap = classPropertyIndex.get(theCachedClass);
         if (propertyMap == null) {
             // GROOVY-6903: May happen in some special environment, like under Android, due
             // to classloading issues
-            propertyMap = new SingleKeyHashMap();
+            propertyMap = new LinkedHashMap<>();
         }
         // simply return the values of the metaproperty map as a List
-        List ret = new ArrayList(propertyMap.size());
-        for (ComplexKeyHashMap.EntryIterator iter = propertyMap.getEntrySetIterator(); iter.hasNext(); ) {
-            MetaProperty element = (MetaProperty) ((SingleKeyHashMap.Entry) iter.next()).value;
+        List<MetaProperty> ret = new ArrayList<>(propertyMap.size());
+        for (Map.Entry<String, MetaProperty> stringMetaPropertyEntry : propertyMap.entrySet()) {
+            MetaProperty element = stringMetaPropertyEntry.getValue();
             if (element instanceof CachedField) continue;
             // filter out DGM beans
             if (element instanceof MetaBeanProperty) {
@@ -2331,23 +2330,21 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
      *
      * @param propertyDescriptors the property descriptors
      */
-    @SuppressWarnings("unchecked")
     private void setupProperties(PropertyDescriptor[] propertyDescriptors) {
         if (theCachedClass.isInterface) {
             LinkedList<CachedClass> superClasses = new LinkedList<>();
             superClasses.add(ReflectionCache.OBJECT_CLASS);
-            Set interfaces = theCachedClass.getInterfaces();
+            LinkedList<CachedClass> superInterfaces = new LinkedList<>(theCachedClass.getInterfaces());
 
-            LinkedList<CachedClass> superInterfaces = new LinkedList<CachedClass>(interfaces);
             // sort interfaces so that we may ensure a deterministic behaviour in case of
             // ambiguous fields (class implementing two interfaces using the same field)
             if (superInterfaces.size() > 1) {
                 superInterfaces.sort(CACHED_CLASS_NAME_COMPARATOR);
             }
 
-            SingleKeyHashMap iPropertyIndex = classPropertyIndex.getNotNull(theCachedClass);
+            Map<String, MetaProperty> iPropertyIndex = classPropertyIndex.computeIfAbsent(theCachedClass, k -> new LinkedHashMap<>());
             for (CachedClass iclass : superInterfaces) {
-                SingleKeyHashMap sPropertyIndex = classPropertyIndex.getNotNull(iclass);
+                Map<String, MetaProperty> sPropertyIndex = classPropertyIndex.computeIfAbsent(iclass, k -> new LinkedHashMap<>());
                 copyNonPrivateFields(sPropertyIndex, iPropertyIndex, null);
                 addFields(iclass, iPropertyIndex);
             }
@@ -2359,21 +2356,22 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
             makeStaticPropertyIndex();
         } else {
             LinkedList<CachedClass> superClasses = getSuperClasses();
-            LinkedList<CachedClass> interfaces = new LinkedList<>(theCachedClass.getInterfaces());
+            LinkedList<CachedClass> superInterfaces = new LinkedList<>(theCachedClass.getInterfaces());
+
             // sort interfaces so that we may ensure a deterministic behaviour in case of
             // ambiguous fields (class implementing two interfaces using the same field)
-            if (interfaces.size() > 1) {
-                interfaces.sort(CACHED_CLASS_NAME_COMPARATOR);
+            if (superInterfaces.size() > 1) {
+                superInterfaces.sort(CACHED_CLASS_NAME_COMPARATOR);
             }
 
             // if this an Array, then add the special read-only "length" property
             if (theCachedClass.isArray) {
-                SingleKeyHashMap map = new SingleKeyHashMap();
+                LinkedHashMap<String, MetaProperty> map = new LinkedHashMap<>();
                 map.put("length", arrayLengthProperty);
                 classPropertyIndex.put(theCachedClass, map);
             }
 
-            inheritStaticInterfaceFields(superClasses, new LinkedHashSet(interfaces));
+            inheritStaticInterfaceFields(superClasses, new LinkedHashSet<>(superInterfaces));
             inheritFields(superClasses);
 
             applyPropertyDescriptors(propertyDescriptors);
@@ -2387,11 +2385,9 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
     }
 
     private void makeStaticPropertyIndex() {
-        SingleKeyHashMap propertyMap = classPropertyIndex.getNotNull(theCachedClass);
-        for (ComplexKeyHashMap.EntryIterator iter = propertyMap.getEntrySetIterator(); iter.hasNext(); ) {
-            SingleKeyHashMap.Entry entry = ((SingleKeyHashMap.Entry) iter.next());
-
-            MetaProperty mp = (MetaProperty) entry.getValue();
+        LinkedHashMap<String, MetaProperty> propertyMap = classPropertyIndex.computeIfAbsent(theCachedClass, k -> new LinkedHashMap<>());
+        for (Map.Entry<String, MetaProperty> entry : propertyMap.entrySet()) {
+            MetaProperty mp = entry.getValue();
             if (mp instanceof CachedField) {
                 CachedField mfp = (CachedField) mp;
                 if (!mfp.isStatic()) continue;
@@ -2458,32 +2454,29 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
         return result;
     }
 
-    private void copyClassPropertyIndexForSuper(Index dest) {
-        for (ComplexKeyHashMap.EntryIterator iter = classPropertyIndex.getEntrySetIterator(); iter.hasNext(); ) {
-            SingleKeyHashMap.Entry entry = (SingleKeyHashMap.Entry) iter.next();
-            SingleKeyHashMap newVal = new SingleKeyHashMap();
-            dest.put((CachedClass) entry.getKey(), newVal);
+    private void copyClassPropertyIndexForSuper(Map<CachedClass, LinkedHashMap<String, MetaProperty>> dest) {
+        for (Map.Entry<CachedClass, LinkedHashMap<String, MetaProperty>> entry : classPropertyIndex.entrySet()) {
+            LinkedHashMap<String, MetaProperty> newVal = new LinkedHashMap<>();
+            dest.put(entry.getKey(), newVal);
         }
     }
 
-    private void inheritStaticInterfaceFields(LinkedList superClasses, Set interfaces) {
-        for (Object anInterface : interfaces) {
-            CachedClass iclass = (CachedClass) anInterface;
-            SingleKeyHashMap iPropertyIndex = classPropertyIndex.getNotNull(iclass);
+    private void inheritStaticInterfaceFields(List<CachedClass> superClasses, Set<CachedClass> interfaces) {
+        for (CachedClass iclass : interfaces) {
+            LinkedHashMap<String, MetaProperty> iPropertyIndex = classPropertyIndex.computeIfAbsent(iclass, k -> new LinkedHashMap<>());
             addFields(iclass, iPropertyIndex);
-            for (Object superClass : superClasses) {
-                CachedClass sclass = (CachedClass) superClass;
-                if (!iclass.getTheClass().isAssignableFrom(sclass.getTheClass())) continue;
-                SingleKeyHashMap sPropertyIndex = classPropertyIndex.getNotNull(sclass);
+            for (CachedClass superClass : superClasses) {
+                if (!iclass.getTheClass().isAssignableFrom(superClass.getTheClass())) continue;
+                LinkedHashMap<String, MetaProperty> sPropertyIndex = classPropertyIndex.computeIfAbsent(superClass, k -> new LinkedHashMap<>());
                 copyNonPrivateFields(iPropertyIndex, sPropertyIndex, null);
             }
         }
     }
 
     private void inheritFields(LinkedList<CachedClass> superClasses) {
-        SingleKeyHashMap last = null;
+        LinkedHashMap<String, MetaProperty> last = null;
         for (CachedClass klass : superClasses) {
-            SingleKeyHashMap propertyIndex = classPropertyIndex.getNotNull(klass);
+            LinkedHashMap<String, MetaProperty> propertyIndex = classPropertyIndex.computeIfAbsent(klass, k -> new LinkedHashMap<>());
             if (last != null) {
                 copyNonPrivateFields(last, propertyIndex, klass);
             }
@@ -2492,15 +2485,14 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
         }
     }
 
-    private static void addFields(CachedClass klass, SingleKeyHashMap propertyIndex) {
+    private static void addFields(CachedClass klass, Map<String, MetaProperty> propertyIndex) {
         for (CachedField field : klass.getFields()) {
             propertyIndex.put(field.getName(), field);
         }
     }
 
-    private static void copyNonPrivateFields(SingleKeyHashMap from, SingleKeyHashMap to, @Nullable CachedClass klass) {
-        for (ComplexKeyHashMap.EntryIterator it = from.getEntrySetIterator(); it.hasNext(); ) {
-            SingleKeyHashMap.Entry entry = (SingleKeyHashMap.Entry) it.next();
+    private static void copyNonPrivateFields(Map<String, MetaProperty> from, Map<String, MetaProperty> to, @Nullable CachedClass klass) {
+        for (Map.Entry<String, MetaProperty> entry : from.entrySet()) {
             CachedField field = (CachedField) entry.getValue();
             int modifiers = field.getModifiers();
             if (Modifier.isPublic(modifiers) || Modifier.isProtected(modifiers) || (!Modifier.isPrivate(modifiers)
@@ -2510,11 +2502,11 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
         }
     }
 
-    private void applyStrayPropertyMethods(LinkedList<CachedClass> superClasses, Index classPropertyIndex, boolean isThis) {
+    private void applyStrayPropertyMethods(LinkedList<CachedClass> superClasses, Map<CachedClass, LinkedHashMap<String, MetaProperty>> classPropertyIndex, boolean isThis) {
         // now look for any stray getters that may be used to define a property
         for (CachedClass klass : superClasses) {
             MetaMethodIndex.Header header = metaMethodIndex.getHeader(klass.getTheClass());
-            SingleKeyHashMap propertyIndex = classPropertyIndex.getNotNull(klass);
+            Map<String, MetaProperty> propertyIndex = classPropertyIndex.computeIfAbsent(klass, k -> new LinkedHashMap<>());
             for (MetaMethodIndex.Entry e = header.head; e != null; e = e.nextClassEntry) {
                 String methodName = e.name;
                 // name too short?
@@ -2598,9 +2590,9 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
         }
     }
 
-    private static void createMetaBeanProperty(SingleKeyHashMap propertyIndex, String propName, boolean isGetter, MetaMethod propertyMethod) {
+    private static void createMetaBeanProperty(Map<String, MetaProperty> propertyIndex, String propName, boolean isGetter, MetaMethod propertyMethod) {
         // is this property already accounted for?
-        MetaProperty mp = (MetaProperty) propertyIndex.get(propName);
+        MetaProperty mp = propertyIndex.get(propName);
         MetaProperty newMp = makeReplacementMetaProperty(mp, propName, isGetter, propertyMethod);
         if (newMp != mp) {
             propertyIndex.put(propName, newMp);
@@ -2654,10 +2646,10 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
         if (staticProperty != null) {
             staticPropertyIndex.put(mp.getName(), mp);
         } else {
-            SingleKeyHashMap propertyMap = classPropertyIndex.getNotNull(theCachedClass);
+            LinkedHashMap<String, MetaProperty> propertyMap = classPropertyIndex.computeIfAbsent(theCachedClass, k -> new LinkedHashMap<>());
             //keep field
             CachedField field;
-            MetaProperty old = (MetaProperty) propertyMap.get(mp.getName());
+            MetaProperty old = propertyMap.get(mp.getName());
             if (old != null) {
                 if (old instanceof MetaBeanProperty) {
                     field = ((MetaBeanProperty) old).getField();
@@ -2851,13 +2843,13 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
 
         CachedClass clazz = ReflectionCache.getCachedClass(_clazz);
         while (true) {
-            SingleKeyHashMap propertyMap;
+            Map<String, MetaProperty> propertyMap;
             if (useStatic) {
                 propertyMap = staticPropertyIndex;
             } else if (useSuper) {
-                propertyMap = classPropertyIndexForSuper.getNullable(clazz);
+                propertyMap = classPropertyIndexForSuper.get(clazz);
             } else {
-                propertyMap = classPropertyIndex.getNullable(clazz);
+                propertyMap = classPropertyIndex.get(clazz);
             }
             if (propertyMap == null) {
                 if (clazz != theCachedClass) {
@@ -2867,22 +2859,22 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
                     return null;
                 }
             }
-            return (MetaProperty) propertyMap.get(name);
+            return propertyMap.get(name);
         }
     }
 
     private MetaProperty getMetaProperty(String name, boolean useStatic) {
         CachedClass clazz = theCachedClass;
-        SingleKeyHashMap propertyMap;
+        Map<String, MetaProperty> propertyMap;
         if (useStatic) {
             propertyMap = staticPropertyIndex;
         } else {
-            propertyMap = classPropertyIndex.getNullable(clazz);
+            propertyMap = classPropertyIndex.get(clazz);
         }
         if (propertyMap == null) {
             return null;
         }
-        return (MetaProperty) propertyMap.get(name);
+        return propertyMap.get(name);
     }
 
     /**
@@ -3902,6 +3894,7 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
         metaMethodIndex.clearCaches();
     }
 
+    @Deprecated
     private static final SingleKeyHashMap.Copier NAME_INDEX_COPIER = value -> {
         if (value instanceof FastArray) {
             return ((FastArray) value).copy();
@@ -3910,8 +3903,13 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
         }
     };
 
+    @Deprecated
     private static final SingleKeyHashMap.Copier METHOD_INDEX_COPIER = value -> SingleKeyHashMap.copy(new SingleKeyHashMap(false), (SingleKeyHashMap) value, NAME_INDEX_COPIER);
 
+    /**
+     * @deprecated use {@link LinkedHashMap} instead
+     */
+    @Deprecated
     static class MethodIndex extends Index {
         public MethodIndex(boolean b) {
             super(false);
@@ -3934,6 +3932,10 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
         }
     }
 
+    /**
+     * @deprecated use {@link LinkedHashMap} instead
+     */
+    @Deprecated
     public static class Index extends SingleKeyHashMap {
 
         public Index(int size) {
diff --git a/src/main/java/org/codehaus/groovy/ast/ClassHelper.java b/src/main/java/org/codehaus/groovy/ast/ClassHelper.java
index 17bcc8d..54b320f 100644
--- a/src/main/java/org/codehaus/groovy/ast/ClassHelper.java
+++ b/src/main/java/org/codehaus/groovy/ast/ClassHelper.java
@@ -52,7 +52,7 @@ import org.codehaus.groovy.runtime.GeneratedClosure;
 import org.codehaus.groovy.runtime.GeneratedLambda;
 import org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport;
 import org.codehaus.groovy.transform.trait.Traits;
-import org.codehaus.groovy.util.ManagedConcurrentMap;
+import org.codehaus.groovy.util.ManagedIdentityConcurrentMap;
 import org.codehaus.groovy.util.ReferenceBundle;
 import org.codehaus.groovy.vmplugin.VMPluginFactory;
 import org.objectweb.asm.Opcodes;
@@ -408,7 +408,7 @@ public class ClassHelper {
     }
 
     static class ClassHelperCache {
-        static ManagedConcurrentMap<Class, SoftReference<ClassNode>> classCache = new ManagedConcurrentMap<Class, SoftReference<ClassNode>>(ReferenceBundle.getWeakBundle());
+        static ManagedIdentityConcurrentMap<Class, SoftReference<ClassNode>> classCache = new ManagedIdentityConcurrentMap<Class, SoftReference<ClassNode>>(ReferenceBundle.getWeakBundle());
     }
 
     public static boolean isSAMType(final ClassNode type) {
diff --git a/src/main/java/org/codehaus/groovy/reflection/ClassInfo.java b/src/main/java/org/codehaus/groovy/reflection/ClassInfo.java
index e55b2ed..b0c00e1 100644
--- a/src/main/java/org/codehaus/groovy/reflection/ClassInfo.java
+++ b/src/main/java/org/codehaus/groovy/reflection/ClassInfo.java
@@ -46,7 +46,7 @@ import org.codehaus.groovy.util.Finalizable;
 import org.codehaus.groovy.util.LazyReference;
 import org.codehaus.groovy.util.LockableObject;
 import org.codehaus.groovy.util.ManagedConcurrentLinkedQueue;
-import org.codehaus.groovy.util.ManagedConcurrentMap;
+import org.codehaus.groovy.util.ManagedIdentityConcurrentMap;
 import org.codehaus.groovy.util.ManagedReference;
 import org.codehaus.groovy.util.ReferenceBundle;
 import org.codehaus.groovy.vmplugin.VMPluginFactory;
@@ -82,7 +82,7 @@ public class ClassInfo implements Finalizable {
     private ManagedReference<MetaClass> weakMetaClass;
     MetaMethod[] dgmMetaMethods = MetaMethod.EMPTY_ARRAY;
     MetaMethod[] newMetaMethods = MetaMethod.EMPTY_ARRAY;
-    private ManagedConcurrentMap<Object, MetaClass> perInstanceMetaClassMap;
+    private ManagedIdentityConcurrentMap<Object, MetaClass> perInstanceMetaClassMap;
 
     private static final ReferenceBundle softBundle = ReferenceBundle.getSoftBundle();
     private static final ReferenceBundle weakBundle = ReferenceBundle.getWeakBundle();
@@ -409,7 +409,7 @@ public class ClassInfo implements Finalizable {
 
         if (metaClass != null) {
             if (perInstanceMetaClassMap == null)
-              perInstanceMetaClassMap = new ManagedConcurrentMap<Object, MetaClass>(ReferenceBundle.getWeakBundle());
+              perInstanceMetaClassMap = new ManagedIdentityConcurrentMap<Object, MetaClass>(ReferenceBundle.getWeakBundle());
 
             perInstanceMetaClassMap.put(obj, metaClass);
         }
diff --git a/src/main/java/org/codehaus/groovy/reflection/GroovyClassValuePreJava7.java b/src/main/java/org/codehaus/groovy/reflection/GroovyClassValuePreJava7.java
index 02f893c..7b95d64 100644
--- a/src/main/java/org/codehaus/groovy/reflection/GroovyClassValuePreJava7.java
+++ b/src/main/java/org/codehaus/groovy/reflection/GroovyClassValuePreJava7.java
@@ -28,6 +28,7 @@ import org.codehaus.groovy.util.ReferenceBundle;
  *
  * @param <T>
  */
+@Deprecated
 class GroovyClassValuePreJava7<T> implements GroovyClassValue<T> {
 	private static final ReferenceBundle weakBundle = ReferenceBundle.getWeakBundle();
 
diff --git a/src/main/java/org/codehaus/groovy/reflection/MixinInMetaClass.java b/src/main/java/org/codehaus/groovy/reflection/MixinInMetaClass.java
index afaf956..f9763e1 100644
--- a/src/main/java/org/codehaus/groovy/reflection/MixinInMetaClass.java
+++ b/src/main/java/org/codehaus/groovy/reflection/MixinInMetaClass.java
@@ -32,7 +32,7 @@ import org.codehaus.groovy.runtime.metaclass.MixedInMetaClass;
 import org.codehaus.groovy.runtime.metaclass.MixinInstanceMetaMethod;
 import org.codehaus.groovy.runtime.metaclass.MixinInstanceMetaProperty;
 import org.codehaus.groovy.runtime.metaclass.NewInstanceMetaMethod;
-import org.codehaus.groovy.util.ManagedConcurrentMap;
+import org.codehaus.groovy.util.ManagedIdentityConcurrentMap;
 import org.codehaus.groovy.util.ReferenceBundle;
 
 import java.lang.reflect.Modifier;
@@ -40,19 +40,18 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
 
-public class MixinInMetaClass extends ManagedConcurrentMap {
+public class MixinInMetaClass {
     final ExpandoMetaClass emc;
     final CachedClass mixinClass;
     final CachedConstructor constructor;
-
-    private static final ReferenceBundle softBundle = ReferenceBundle.getSoftBundle();
+    private final ManagedIdentityConcurrentMap managedIdentityConcurrentMap =
+            new ManagedIdentityConcurrentMap(ReferenceBundle.getSoftBundle());
 
     public MixinInMetaClass(ExpandoMetaClass emc, CachedClass mixinClass) {
-        super(softBundle);
         this.emc = emc;
         this.mixinClass = mixinClass;
 
-        constructor = findDefaultConstructor(mixinClass);
+        this.constructor = findDefaultConstructor(mixinClass);
         emc.addMixinClass(this);
     }
 
@@ -70,20 +69,20 @@ public class MixinInMetaClass extends ManagedConcurrentMap {
     }
 
     public synchronized Object getMixinInstance(Object object) {
-        Object mixinInstance = get(object);
+        Object mixinInstance = managedIdentityConcurrentMap.get(object);
         if (mixinInstance == null) {
             mixinInstance = constructor.invoke(MetaClassHelper.EMPTY_ARRAY);
             new MixedInMetaClass(mixinInstance, object);
-            put(object, mixinInstance);
+            managedIdentityConcurrentMap.put(object, mixinInstance);
         }
         return mixinInstance;
     }
 
     public synchronized void setMixinInstance(Object object, Object mixinInstance) {
         if (mixinInstance == null) {
-            remove(object);
+            managedIdentityConcurrentMap.remove(object);
         } else {
-            put(object, mixinInstance);
+            managedIdentityConcurrentMap.put(object, mixinInstance);
         }
     }
 
diff --git a/src/main/java/org/codehaus/groovy/reflection/ReflectionCache.java b/src/main/java/org/codehaus/groovy/reflection/ReflectionCache.java
index 7f6c525..2b33315 100644
--- a/src/main/java/org/codehaus/groovy/reflection/ReflectionCache.java
+++ b/src/main/java/org/codehaus/groovy/reflection/ReflectionCache.java
@@ -26,8 +26,10 @@ public class ReflectionCache {
         return TypeUtil.autoboxType(type);
     }
 
+    @Deprecated
     static TripleKeyHashMap mopNames = new TripleKeyHashMap();
 
+    @Deprecated // the method is never called
     public static String getMOPMethodName(CachedClass declaringClass, String name, boolean useThis) {
         TripleKeyHashMap.Entry mopNameEntry = mopNames.getOrPut(declaringClass, name, useThis);
         if (mopNameEntry.value == null) {
diff --git a/src/main/java/org/codehaus/groovy/runtime/memoize/MemoizeCache.java b/src/main/java/org/codehaus/groovy/runtime/memoize/MemoizeCache.java
index c525919..dfa4438 100644
--- a/src/main/java/org/codehaus/groovy/runtime/memoize/MemoizeCache.java
+++ b/src/main/java/org/codehaus/groovy/runtime/memoize/MemoizeCache.java
@@ -44,7 +44,7 @@ public interface MemoizeCache<K, V> {
      * Try to get the value from cache.
      * If not found, create the value by {@link ValueProvider} and put it into the cache, at last return the value.
      *
-     * @param key
+     * @param key the key to look up
      * @param valueProvider provide the value if the associated value not found
      * @return the cached value
      */
diff --git a/src/main/java/org/codehaus/groovy/runtime/metaclass/ThreadManagedMetaBeanProperty.java b/src/main/java/org/codehaus/groovy/runtime/metaclass/ThreadManagedMetaBeanProperty.java
index 5074908..8cae32f 100644
--- a/src/main/java/org/codehaus/groovy/runtime/metaclass/ThreadManagedMetaBeanProperty.java
+++ b/src/main/java/org/codehaus/groovy/runtime/metaclass/ThreadManagedMetaBeanProperty.java
@@ -23,7 +23,7 @@ import groovy.lang.MetaBeanProperty;
 import groovy.lang.MetaMethod;
 import org.codehaus.groovy.reflection.CachedClass;
 import org.codehaus.groovy.reflection.ReflectionCache;
-import org.codehaus.groovy.util.ManagedConcurrentMap;
+import org.codehaus.groovy.util.ManagedIdentityConcurrentMap;
 import org.codehaus.groovy.util.ReferenceBundle;
 
 import java.lang.reflect.Modifier;
@@ -39,9 +39,9 @@ import java.util.concurrent.ConcurrentHashMap;
  * @since 1.5
  */
 public class ThreadManagedMetaBeanProperty extends MetaBeanProperty {
-    private static final ConcurrentHashMap<String,ManagedConcurrentMap> PROPNAME_TO_MAP = new ConcurrentHashMap<String, ManagedConcurrentMap>();
+    private static final ConcurrentHashMap<String,ManagedIdentityConcurrentMap> PROPNAME_TO_MAP = new ConcurrentHashMap<String, ManagedIdentityConcurrentMap>();
 
-    private final ManagedConcurrentMap instance2Prop;
+    private final ManagedIdentityConcurrentMap instance2Prop;
 
     private final Class declaringClass;
     private final ThreadBoundGetter getter;
@@ -117,11 +117,11 @@ public class ThreadManagedMetaBeanProperty extends MetaBeanProperty {
         instance2Prop = getInstance2PropName(name);
     }
 
-    private static ManagedConcurrentMap getInstance2PropName(String name) {
-        ManagedConcurrentMap res = PROPNAME_TO_MAP.get(name);
+    private static ManagedIdentityConcurrentMap getInstance2PropName(String name) {
+        ManagedIdentityConcurrentMap res = PROPNAME_TO_MAP.get(name);
         if (res == null) {
-            res = new ManagedConcurrentMap(SOFT_BUNDLE);
-            ManagedConcurrentMap ores = PROPNAME_TO_MAP.putIfAbsent(name, res);
+            res = new ManagedIdentityConcurrentMap(SOFT_BUNDLE);
+            ManagedIdentityConcurrentMap ores = PROPNAME_TO_MAP.putIfAbsent(name, res);
             if (ores != null)
               return ores;
         }
@@ -176,7 +176,7 @@ public class ThreadManagedMetaBeanProperty extends MetaBeanProperty {
            * @see groovy.lang.MetaMethod#invoke(java.lang.Object, java.lang.Object[])
            */
         public Object invoke(Object object, Object[] arguments) {
-            return instance2Prop.getOrPut(object, getInitialValue()).getValue();
+            return instance2Prop.getOrPut(object, getInitialValue());
         }
     }
 
diff --git a/src/main/java/org/codehaus/groovy/util/AbstractConcurrentMap.java b/src/main/java/org/codehaus/groovy/util/AbstractConcurrentMap.java
index 6168877..d67fd88 100644
--- a/src/main/java/org/codehaus/groovy/util/AbstractConcurrentMap.java
+++ b/src/main/java/org/codehaus/groovy/util/AbstractConcurrentMap.java
@@ -18,6 +18,7 @@
  */
 package org.codehaus.groovy.util;
 
+@Deprecated
 public abstract class AbstractConcurrentMap<K, V> extends AbstractConcurrentMapBase {
 
     public AbstractConcurrentMap(Object segmentInfo) {
diff --git a/src/main/java/org/codehaus/groovy/util/AbstractConcurrentMapBase.java b/src/main/java/org/codehaus/groovy/util/AbstractConcurrentMapBase.java
index 01f84af..57ac68e 100644
--- a/src/main/java/org/codehaus/groovy/util/AbstractConcurrentMapBase.java
+++ b/src/main/java/org/codehaus/groovy/util/AbstractConcurrentMapBase.java
@@ -21,6 +21,7 @@ package org.codehaus.groovy.util;
 import java.util.Collection;
 import java.util.LinkedList;
 
+@Deprecated
 public abstract class AbstractConcurrentMapBase {
     protected static final int MAXIMUM_CAPACITY = 1 << 30;
     static final int MAX_SEGMENTS = 1 << 16;
diff --git a/src/main/java/org/codehaus/groovy/util/ComplexKeyHashMap.java b/src/main/java/org/codehaus/groovy/util/ComplexKeyHashMap.java
index c74f0bb..5d8a1b8 100644
--- a/src/main/java/org/codehaus/groovy/util/ComplexKeyHashMap.java
+++ b/src/main/java/org/codehaus/groovy/util/ComplexKeyHashMap.java
@@ -21,6 +21,7 @@ package org.codehaus.groovy.util;
 import java.util.Arrays;
 import java.util.NoSuchElementException;
 
+@Deprecated
 public class ComplexKeyHashMap
 {
   public static class Entry {
diff --git a/src/main/java/org/codehaus/groovy/util/ManagedConcurrentMap.java b/src/main/java/org/codehaus/groovy/util/ManagedConcurrentMap.java
index d1cf760..7329711 100644
--- a/src/main/java/org/codehaus/groovy/util/ManagedConcurrentMap.java
+++ b/src/main/java/org/codehaus/groovy/util/ManagedConcurrentMap.java
@@ -18,6 +18,7 @@
  */
 package org.codehaus.groovy.util;
 
+@Deprecated
 public class ManagedConcurrentMap<K,V> extends AbstractConcurrentMap<K,V> {
     protected ReferenceBundle bundle;
     public ManagedConcurrentMap(ReferenceBundle bundle) {
diff --git a/src/main/java/org/codehaus/groovy/util/ManagedIdentityConcurrentMap.java b/src/main/java/org/codehaus/groovy/util/ManagedIdentityConcurrentMap.java
new file mode 100644
index 0000000..2736244
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/util/ManagedIdentityConcurrentMap.java
@@ -0,0 +1,149 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.util;
+
+import java.util.Collection;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * This is a basic implementation of a map able to forget its keys. This
+ * map uses internally a ConcurrentHashMap, thus should be safe for concurrency.
+ * hashcode and equals are used to find the entries and should thus be implemented
+ * properly for the keys. This map does not support null keys.
+ *
+ * @param <K> the key type
+ * @param <V> the value type
+ * @since 4.0.0
+ */
+public class ManagedIdentityConcurrentMap<K, V> {
+    private final ConcurrentHashMap<ManagedReference<K>, V> internalMap;
+    private final ReferenceBundle bundle;
+
+    public ManagedIdentityConcurrentMap(ReferenceBundle bundle) {
+        this.internalMap = new ConcurrentHashMap<>();
+        this.bundle = bundle;
+    }
+
+    /**
+     * Returns the value stored for the given key at the point of call.
+     *
+     * @param key a non null key
+     * @return the value stored in the map for the given key
+     */
+    public V get(K key) {
+        return internalMap.get(new ManagedIdentityKey<K>(key));
+    }
+
+    /**
+     * Sets a new value for a given key. an older value is overwritten.
+     *
+     * @param key   a non null key
+     * @param value the new value
+     */
+    public V put(final K key, V value) {
+        return internalMap.put(new ManagedIdentityKey<K>(key), value);
+    }
+
+    /**
+     * Returns the values of the map
+     */
+    public Collection<V> values() {
+        return internalMap.values();
+    }
+
+    /**
+     * Remove the key specified entry
+     *
+     * @param key the key to look up
+     * @return the removed value
+     */
+    public V remove(K key) {
+        return internalMap.remove(new ManagedIdentityKey<K>(key));
+    }
+
+    /**
+     * Get the key specified value, or put the default value and return it if the key is absent
+     *
+     * @param key the key to look up
+     * @param value the default value if the key is absent
+     * @return the value
+     */
+    public V getOrPut(K key, V value) {
+        return internalMap.computeIfAbsent(new ManagedIdentityKey<K>(key), k -> value);
+    }
+
+    /**
+     * Returns the map size
+     */
+    public Object size() {
+        return internalMap.size();
+    }
+
+    /**
+     * Check if the map is empty or not
+     *
+     * @return {@code true} when the map is empty, otherwise {@code false}
+     */
+    public boolean isEmpty() {
+        return internalMap.isEmpty();
+    }
+
+    /**
+     * Represents identity key of {@link ManagedIdentityConcurrentMap}
+     *
+     * @param <K> the key type
+     */
+    private class ManagedIdentityKey<K> extends ManagedReference<K> {
+        private final int hashCode;
+
+        private ManagedIdentityKey(K key) {
+            super(bundle, key);
+            this.hashCode = hash(key);
+        }
+
+        @Override
+        public void finalizeReference() {
+            internalMap.remove(this);
+            super.finalizeReference();
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (!(o instanceof ManagedIdentityKey)) return false;
+            return get() == ((ManagedIdentityKey<?>) o).get();
+        }
+
+        @Override
+        public int hashCode() {
+            return this.hashCode;
+        }
+
+        private int hash(K key) {
+            int h = (null == key) ? 0 : System.identityHashCode(key);
+            h += (h << 15) ^ 0xffffcd7d;
+            h ^= (h >>> 10);
+            h += (h << 3);
+            h ^= (h >>> 6);
+            h += (h << 2) + (h << 14);
+            h ^= (h >>> 16);
+            return h;
+        }
+    }
+}
diff --git a/src/main/java/org/codehaus/groovy/util/SingleKeyHashMap.java b/src/main/java/org/codehaus/groovy/util/SingleKeyHashMap.java
index 974b24b..86e0990 100644
--- a/src/main/java/org/codehaus/groovy/util/SingleKeyHashMap.java
+++ b/src/main/java/org/codehaus/groovy/util/SingleKeyHashMap.java
@@ -18,6 +18,7 @@
  */
 package org.codehaus.groovy.util;
 
+@Deprecated
 public class SingleKeyHashMap extends ComplexKeyHashMap
 {
     public static class Entry extends ComplexKeyHashMap.Entry{
diff --git a/src/main/java/org/codehaus/groovy/util/TripleKeyHashMap.java b/src/main/java/org/codehaus/groovy/util/TripleKeyHashMap.java
index b2d891b..668db9a 100644
--- a/src/main/java/org/codehaus/groovy/util/TripleKeyHashMap.java
+++ b/src/main/java/org/codehaus/groovy/util/TripleKeyHashMap.java
@@ -18,6 +18,7 @@
  */
 package org.codehaus.groovy.util;
 
+@Deprecated
 public class TripleKeyHashMap extends ComplexKeyHashMap
 {
   public static class Entry extends ComplexKeyHashMap.Entry{
diff --git a/src/test/org/codehaus/groovy/util/ManagedIdentityConcurrentMapTest.groovy b/src/test/org/codehaus/groovy/util/ManagedIdentityConcurrentMapTest.groovy
new file mode 100644
index 0000000..d454b3f
--- /dev/null
+++ b/src/test/org/codehaus/groovy/util/ManagedIdentityConcurrentMapTest.groovy
@@ -0,0 +1,60 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.util
+
+
+import org.junit.Test
+
+class ManagedIdentityConcurrentMapTest {
+    @Test
+    void testRemovingEntriesFromMapAfterGC() {
+        def m = new ManagedIdentityConcurrentMap<Object, String>(ReferenceBundle.getWeakBundle())
+        def k1 = new Object()
+        m.put(k1, "a")
+        def k2 = new Object()
+        m.put(k2, "b")
+        def k3 = new Object()
+        m.put(k3, "c")
+
+        assert 3 == m.size()
+
+        // the related entries should be removed after GC happens
+        k1 = null
+        k2 = null
+        k3 = null
+
+        // finalize via GC, which is hard to predicate though it will happen at last
+        for (int i = 0; i < 20; i++) {
+            System.gc()
+
+            if (m.values().size() == 0) {
+                break
+            }
+
+            Thread.sleep(100)
+        }
+
+        // finalize manually
+        if (!m.isEmpty()) {
+            m.internalMap.keySet().stream().forEach(e -> e.finalizeReference())
+        }
+
+        assert m.isEmpty()
+    }
+}
diff --git a/subprojects/groovy-json/src/spec/test/json/JsonTest.groovy b/subprojects/groovy-json/src/spec/test/json/JsonTest.groovy
index 1069af1..02b6863 100644
--- a/subprojects/groovy-json/src/spec/test/json/JsonTest.groovy
+++ b/subprojects/groovy-json/src/spec/test/json/JsonTest.groovy
@@ -120,7 +120,7 @@ class JsonTest extends GroovyTestCase {
             .excludeFieldsByType(URL)
             .build()
 
-        assert generator.toJson(person) == '{"dob":"1984@12","name":"John"}'
+        assert generator.toJson(person) == '{"name":"John","dob":"1984@12"}'
         // end::json_output_generator[]
         '''
     }
@@ -148,7 +148,7 @@ class JsonTest extends GroovyTestCase {
             }
             .build()
 
-        assert generator.toJson(person) == '{"favoriteUrl":"groovy-lang.org","name":"John"}'
+        assert generator.toJson(person) == '{"name":"John","favoriteUrl":"groovy-lang.org"}'
 
         // No key available when generating a JSON Array
         def list = [new URL('http://groovy-lang.org/json.html#_jsonoutput')]
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/JsonOutputTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/JsonOutputTest.groovy
index 3ed54bf..20c061d 100644
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/JsonOutputTest.groovy
+++ b/subprojects/groovy-json/src/test/groovy/groovy/json/JsonOutputTest.groovy
@@ -306,30 +306,30 @@ class JsonOutputTest extends GroovyTestCase {
                 "name": "Paris",
                 "districts": [
                     {
+                        "number": 1,
                         "streets": [
                             {
-                                "kind": "street",
-                                "streetName": "Saint-Honore"
+                                "streetName": "Saint-Honore",
+                                "kind": "street"
                             },
                             {
-                                "kind": "avenue",
-                                "streetName": "de l'Opera"
+                                "streetName": "de l'Opera",
+                                "kind": "avenue"
                             }
-                        ],
-                        "number": 1
+                        ]
                     },
                     {
+                        "number": 2,
                         "streets": [
                             {
-                                "kind": "boulevard",
-                                "streetName": "des Italiens"
+                                "streetName": "des Italiens",
+                                "kind": "boulevard"
                             },
                             {
-                                "kind": "boulevard",
-                                "streetName": "Bonne Nouvelle"
+                                "streetName": "Bonne Nouvelle",
+                                "kind": "boulevard"
                             }
-                        ],
-                        "number": 2
+                        ]
                     }
                 ]
             }'''.stripIndent()
@@ -350,12 +350,12 @@ class JsonOutputTest extends GroovyTestCase {
     void testObjectWithDeclaredPropertiesField() {
         def person = new JsonObject(name: "pillow", properties: [state: "fluffy", color: "white"])
         def json = toJson(person)
-        assert json == '{"properties":{"state":"fluffy","color":"white"},"name":"pillow"}'
+        assert json == '{"name":"pillow","properties":{"state":"fluffy","color":"white"}}'
     }
 
     void testGROOVY5494() {
         def json = toJson(new JsonFoo(name: "foo"))
-        assert json == '{"properties":0,"name":"foo"}'
+        assert json == '{"name":"foo","properties":0}'
     }
 
     void testCharacter() {