Groovy
  1. Groovy
  2. GROOVY-2961

ConcurrentModificationException in CachedClass when running same script in multiple threads

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Cannot Reproduce
    • Affects Version/s: 1.5.6
    • Fix Version/s: None
    • Component/s: class generator
    • Labels:
      None

      Description

      If getInterfaces() is called from another thread, before CachedClass has been initialized, an exception maybe thrown. CachedClass should be put into the shared CACHED_CLASS_MAP after it has been initialized and not before. The initialize block may need to be synchronized to prevent a possible race condition.

      java.util.ConcurrentModificationException
              at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
              at java.util.HashMap$KeyIterator.next(HashMap.java:828)
              at java.util.AbstractCollection.addAll(AbstractCollection.java:305)
              at org.codehaus.groovy.reflection.CachedClass.getInterfaces(CachedClass.java:70)
              at org.codehaus.groovy.reflection.CachedClass.initialize(CachedClass.java:134)
              at org.codehaus.groovy.reflection.ReflectionCache.getCachedClass(ReflectionCache.java:276)
              at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getGlobalMetaClass(MetaClassRegistryImpl.java:250)
              at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.access$100(MetaClassRegistryImpl.java:45)
              at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl$LocallyKnownClasses.getFromGlobal(MetaClassRegistryImpl.java:112)
              at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl$LocallyKnownClasses.getMetaClass(MetaClassRegistryImpl.java:88)
              at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl$MyThreadLocal.getMetaClass(MetaClassRegistryImpl.java:361)
              at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getMetaClass(MetaClassRegistryImpl.java:265)
              at org.codehaus.groovy.runtime.InvokerHelper.getProperty(InvokerHelper.java:178)
              at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.getProperty(ScriptBytecodeAdapter.java:477)
      

      — CachedClass.java:70 —

          private Set interfaces;
      
          public Set getInterfaces() {
              if (interfaces == null)  {
                  interfaces = new HashSet (0);
      
                  if (getCachedClass().isInterface())
                    interfaces.add(this);
      
                  Class[] classes = getCachedClass().getInterfaces();
                  for (int i = 0; i < classes.length; i++) {
                      final CachedClass aClass = ReflectionCache.getCachedClass(classes[i]);
                      if (!interfaces.contains(aClass))
                        interfaces.addAll(aClass.getInterfaces());
                  }
      
                  final CachedClass superClass = getCachedSuperClass();
                  if (superClass != null)
                    interfaces.addAll(superClass.getInterfaces());
              }
              return interfaces;
          }
      

      — ReflectionCache.java:276 —

                  CachedClass fasterCachedClass = null;
      
                  // Double-check put.
                  synchronized (CACHED_CLASS_MAP) {
                      ref = (SoftReference) CACHED_CLASS_MAP.get(klazz);
      
                      if (ref == null || (fasterCachedClass = (CachedClass) ref.get()) == null) {
                          CACHED_CLASS_MAP.put(klazz, new SoftReference(cachedClass));
                      } else {
                          // We must use the one that there first, we should be able to safely toss the one we made.
                          // By locking Class we would eliminate this race, but until the design is corrected we risk
                          // deadlock.
                          cachedClass = fasterCachedClass;
                      }
                  }
      
                  if (null == fasterCachedClass) {
                      // We've got a new CacheClass, now get loaded into the assignableMap.
                  	cachedClass.initialize();
                  }
      

        Activity

        James Leigh created issue -
        Jochen Theodorou made changes -
        Field Original Value New Value
        Fix Version/s 1.6-beta-2 [ 14261 ]
        Fix Version/s 1.5.7 [ 14242 ]
        Assignee Jochen Theodorou [ blackdrag ] Alex Tkachman [ ait ]
        Guillaume Delcroix made changes -
        Fix Version/s 1.5.8 [ 14630 ]
        Fix Version/s 1.6-beta-2 [ 14261 ]
        Fix Version/s 1.5.7 [ 14242 ]
        Guillaume Delcroix made changes -
        Fix Version/s 1.5.8 [ 14630 ]
        Fix Version/s 1.6.2 [ 15151 ]
        Guillaume Delcroix made changes -
        Fix Version/s 1.6.3 [ 15251 ]
        Fix Version/s 1.6.2 [ 15151 ]
        Guillaume Delcroix made changes -
        Fix Version/s 1.7-beta-1 [ 14014 ]
        Fix Version/s 1.6.3 [ 15251 ]
        Guillaume Delcroix made changes -
        Fix Version/s 1.7-beta-x [ 15538 ]
        Fix Version/s 1.7-beta-1 [ 14014 ]
        Jochen Theodorou made changes -
        Assignee Alex Tkachman [ ait ]
        Hide
        Chris Braun added a comment -

        I have seen this on 1.5.6 when I have two classes that extend the same class and call newInstance() on each of the classes concurrently.

        HitachiAccessHandleCollector extends HitachiDiscoveryCollector extends BaseCollector
        Thread1 - HitachiAccessHandleCollector.newInstance
        Thread2 - HitachiDiscoveryCollector.newInstance

        Results in race condition and the stack trace as follows:

        2010-08-28 08:30:00,018 ERROR collector-14 [com.akorri.bp.collectionserver.exception.DCSSException] Collector instantiation failed -> class com.akorri.bp.collectionserver.collectors.HitachiAccessHandleCollector
        java.util.ConcurrentModificationException
        at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
        at java.util.HashMap$KeyIterator.next(HashMap.java:828)
        at java.util.AbstractCollection.addAll(AbstractCollection.java:305)
        at org.codehaus.groovy.reflection.CachedClass.getInterfaces(CachedClass.java:75)
        at org.codehaus.groovy.reflection.CachedClass.initialize(CachedClass.java:134)
        at org.codehaus.groovy.reflection.ReflectionCache.getCachedClass(ReflectionCache.java:276)
        at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getGlobalMetaClass(MetaClassRegistryImpl.java:250)
        at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.access$100(MetaClassRegistryImpl.java:45)
        at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl$LocallyKnownClasses.getFromGlobal(MetaClassRegistryImpl.java:112)
        at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl$LocallyKnownClasses.getMetaClass(MetaClassRegistryImpl.java:88)
        at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl$MyThreadLocal.getMetaClass(MetaClassRegistryImpl.java:361)
        at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getMetaClass(MetaClassRegistryImpl.java:265)
        at org.codehaus.groovy.runtime.InvokerHelper.getMetaClass(InvokerHelper.java:729)
        at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.initMetaClass(ScriptBytecodeAdapter.java:799)
        at sun.reflect.GeneratedMethodAccessor137.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86)
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:230)
        at groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1105)
        at org.codehaus.groovy.runtime.InvokerHelper.invokeStaticMethod(InvokerHelper.java:804)
        at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeStaticMethodN(ScriptBytecodeAdapter.java:215)
        at com.akorri.bp.collectionserver.collectors.BaseCollector.(BaseCollector.groovy:100)
        at com.akorri.bp.collectionserver.collectors.HitachiDiscoveryCollector.(HitachiDiscoveryCollector.groovy)
        at com.akorri.bp.collectionserver.collectors.HitachiAccessHandleCollector.(HitachiAccessHandleCollector.groovy)
        at sun.reflect.GeneratedConstructorAccessor329.newInstance(Unknown Source)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
        at java.lang.Class.newInstance0(Class.java:355)
        at java.lang.Class.newInstance(Class.java:308)
        at com.akorri.bp.collectionserver.collector.DcssService.collectNow(DcssService.java:281)

        Show
        Chris Braun added a comment - I have seen this on 1.5.6 when I have two classes that extend the same class and call newInstance() on each of the classes concurrently. HitachiAccessHandleCollector extends HitachiDiscoveryCollector extends BaseCollector Thread1 - HitachiAccessHandleCollector.newInstance Thread2 - HitachiDiscoveryCollector.newInstance Results in race condition and the stack trace as follows: 2010-08-28 08:30:00,018 ERROR collector-14 [com.akorri.bp.collectionserver.exception.DCSSException] Collector instantiation failed -> class com.akorri.bp.collectionserver.collectors.HitachiAccessHandleCollector java.util.ConcurrentModificationException at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793) at java.util.HashMap$KeyIterator.next(HashMap.java:828) at java.util.AbstractCollection.addAll(AbstractCollection.java:305) at org.codehaus.groovy.reflection.CachedClass.getInterfaces(CachedClass.java:75) at org.codehaus.groovy.reflection.CachedClass.initialize(CachedClass.java:134) at org.codehaus.groovy.reflection.ReflectionCache.getCachedClass(ReflectionCache.java:276) at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getGlobalMetaClass(MetaClassRegistryImpl.java:250) at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.access$100(MetaClassRegistryImpl.java:45) at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl$LocallyKnownClasses.getFromGlobal(MetaClassRegistryImpl.java:112) at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl$LocallyKnownClasses.getMetaClass(MetaClassRegistryImpl.java:88) at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl$MyThreadLocal.getMetaClass(MetaClassRegistryImpl.java:361) at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getMetaClass(MetaClassRegistryImpl.java:265) at org.codehaus.groovy.runtime.InvokerHelper.getMetaClass(InvokerHelper.java:729) at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.initMetaClass(ScriptBytecodeAdapter.java:799) at sun.reflect.GeneratedMethodAccessor137.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86) at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:230) at groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1105) at org.codehaus.groovy.runtime.InvokerHelper.invokeStaticMethod(InvokerHelper.java:804) at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeStaticMethodN(ScriptBytecodeAdapter.java:215) at com.akorri.bp.collectionserver.collectors.BaseCollector.(BaseCollector.groovy:100) at com.akorri.bp.collectionserver.collectors.HitachiDiscoveryCollector.(HitachiDiscoveryCollector.groovy) at com.akorri.bp.collectionserver.collectors.HitachiAccessHandleCollector.(HitachiAccessHandleCollector.groovy) at sun.reflect.GeneratedConstructorAccessor329.newInstance(Unknown Source) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) at java.lang.reflect.Constructor.newInstance(Constructor.java:513) at java.lang.Class.newInstance0(Class.java:355) at java.lang.Class.newInstance(Class.java:308) at com.akorri.bp.collectionserver.collector.DcssService.collectNow(DcssService.java:281)
        Jochen Theodorou made changes -
        Parent GROOVY-4683 [ 122027 ]
        Issue Type Bug [ 1 ] Sub-task [ 7 ]
        Jochen Theodorou made changes -
        Issue Type Sub-task [ 7 ] Bug [ 1 ]
        Parent GROOVY-4683 [ 122027 ]
        Guillaume Delcroix made changes -
        Description If getInterfaces() is called from another thread, before CachedClass has been initialized, an exception maybe thrown. CachedClass should be put into the shared CACHED_CLASS_MAP *after* it has been initialized and not before. The initialize block may need to be synchronized to prevent a possible race condition.

        java.util.ConcurrentModificationException
                at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
                at java.util.HashMap$KeyIterator.next(HashMap.java:828)
                at java.util.AbstractCollection.addAll(AbstractCollection.java:305)
                at org.codehaus.groovy.reflection.CachedClass.getInterfaces(CachedClass.java:70)
                at org.codehaus.groovy.reflection.CachedClass.initialize(CachedClass.java:134)
                at org.codehaus.groovy.reflection.ReflectionCache.getCachedClass(ReflectionCache.java:276)
                at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getGlobalMetaClass(MetaClassRegistryImpl.java:250)
                at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.access$100(MetaClassRegistryImpl.java:45)
                at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl$LocallyKnownClasses.getFromGlobal(MetaClassRegistryImpl.java:112)
                at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl$LocallyKnownClasses.getMetaClass(MetaClassRegistryImpl.java:88)
                at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl$MyThreadLocal.getMetaClass(MetaClassRegistryImpl.java:361)
                at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getMetaClass(MetaClassRegistryImpl.java:265)
                at org.codehaus.groovy.runtime.InvokerHelper.getProperty(InvokerHelper.java:178)
                at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.getProperty(ScriptBytecodeAdapter.java:477)

        --- CachedClass.java:70 ---

            private Set interfaces;

            public Set getInterfaces() {
                if (interfaces == null) {
                    interfaces = new HashSet (0);

                    if (getCachedClass().isInterface())
                      interfaces.add(this);

                    Class[] classes = getCachedClass().getInterfaces();
                    for (int i = 0; i < classes.length; i++) {
                        final CachedClass aClass = ReflectionCache.getCachedClass(classes[i]);
                        if (!interfaces.contains(aClass))
                          interfaces.addAll(aClass.getInterfaces());
                    }

                    final CachedClass superClass = getCachedSuperClass();
                    if (superClass != null)
                      interfaces.addAll(superClass.getInterfaces());
                }
                return interfaces;
            }


        --- ReflectionCache.java:276 ---

                    CachedClass fasterCachedClass = null;

                    // Double-check put.
                    synchronized (CACHED_CLASS_MAP) {
                        ref = (SoftReference) CACHED_CLASS_MAP.get(klazz);

                        if (ref == null || (fasterCachedClass = (CachedClass) ref.get()) == null) {
                            CACHED_CLASS_MAP.put(klazz, new SoftReference(cachedClass));
                        } else {
                            // We must use the one that there first, we should be able to safely toss the one we made.
                            // By locking Class we would eliminate this race, but until the design is corrected we risk
                            // deadlock.
                            cachedClass = fasterCachedClass;
                        }
                    }

                    if (null == fasterCachedClass) {
                        // We've got a new CacheClass, now get loaded into the assignableMap.
                     cachedClass.initialize();
                    }
        If getInterfaces() is called from another thread, before CachedClass has been initialized, an exception maybe thrown. CachedClass should be put into the shared CACHED_CLASS_MAP *after* it has been initialized and not before. The initialize block may need to be synchronized to prevent a possible race condition.
        {code}
        java.util.ConcurrentModificationException
                at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
                at java.util.HashMap$KeyIterator.next(HashMap.java:828)
                at java.util.AbstractCollection.addAll(AbstractCollection.java:305)
                at org.codehaus.groovy.reflection.CachedClass.getInterfaces(CachedClass.java:70)
                at org.codehaus.groovy.reflection.CachedClass.initialize(CachedClass.java:134)
                at org.codehaus.groovy.reflection.ReflectionCache.getCachedClass(ReflectionCache.java:276)
                at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getGlobalMetaClass(MetaClassRegistryImpl.java:250)
                at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.access$100(MetaClassRegistryImpl.java:45)
                at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl$LocallyKnownClasses.getFromGlobal(MetaClassRegistryImpl.java:112)
                at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl$LocallyKnownClasses.getMetaClass(MetaClassRegistryImpl.java:88)
                at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl$MyThreadLocal.getMetaClass(MetaClassRegistryImpl.java:361)
                at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getMetaClass(MetaClassRegistryImpl.java:265)
                at org.codehaus.groovy.runtime.InvokerHelper.getProperty(InvokerHelper.java:178)
                at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.getProperty(ScriptBytecodeAdapter.java:477)

        --- CachedClass.java:70 ---

            private Set interfaces;

            public Set getInterfaces() {
                if (interfaces == null) {
                    interfaces = new HashSet (0);

                    if (getCachedClass().isInterface())
                      interfaces.add(this);

                    Class[] classes = getCachedClass().getInterfaces();
                    for (int i = 0; i < classes.length; i++) {
                        final CachedClass aClass = ReflectionCache.getCachedClass(classes[i]);
                        if (!interfaces.contains(aClass))
                          interfaces.addAll(aClass.getInterfaces());
                    }

                    final CachedClass superClass = getCachedSuperClass();
                    if (superClass != null)
                      interfaces.addAll(superClass.getInterfaces());
                }
                return interfaces;
            }


        --- ReflectionCache.java:276 ---

                    CachedClass fasterCachedClass = null;

                    // Double-check put.
                    synchronized (CACHED_CLASS_MAP) {
                        ref = (SoftReference) CACHED_CLASS_MAP.get(klazz);

                        if (ref == null || (fasterCachedClass = (CachedClass) ref.get()) == null) {
                            CACHED_CLASS_MAP.put(klazz, new SoftReference(cachedClass));
                        } else {
                            // We must use the one that there first, we should be able to safely toss the one we made.
                            // By locking Class we would eliminate this race, but until the design is corrected we risk
                            // deadlock.
                            cachedClass = fasterCachedClass;
                        }
                    }

                    if (null == fasterCachedClass) {
                        // We've got a new CacheClass, now get loaded into the assignableMap.
                     cachedClass.initialize();
                    }
        {code}
        Guillaume Delcroix made changes -
        Description If getInterfaces() is called from another thread, before CachedClass has been initialized, an exception maybe thrown. CachedClass should be put into the shared CACHED_CLASS_MAP *after* it has been initialized and not before. The initialize block may need to be synchronized to prevent a possible race condition.
        {code}
        java.util.ConcurrentModificationException
                at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
                at java.util.HashMap$KeyIterator.next(HashMap.java:828)
                at java.util.AbstractCollection.addAll(AbstractCollection.java:305)
                at org.codehaus.groovy.reflection.CachedClass.getInterfaces(CachedClass.java:70)
                at org.codehaus.groovy.reflection.CachedClass.initialize(CachedClass.java:134)
                at org.codehaus.groovy.reflection.ReflectionCache.getCachedClass(ReflectionCache.java:276)
                at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getGlobalMetaClass(MetaClassRegistryImpl.java:250)
                at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.access$100(MetaClassRegistryImpl.java:45)
                at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl$LocallyKnownClasses.getFromGlobal(MetaClassRegistryImpl.java:112)
                at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl$LocallyKnownClasses.getMetaClass(MetaClassRegistryImpl.java:88)
                at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl$MyThreadLocal.getMetaClass(MetaClassRegistryImpl.java:361)
                at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getMetaClass(MetaClassRegistryImpl.java:265)
                at org.codehaus.groovy.runtime.InvokerHelper.getProperty(InvokerHelper.java:178)
                at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.getProperty(ScriptBytecodeAdapter.java:477)

        --- CachedClass.java:70 ---

            private Set interfaces;

            public Set getInterfaces() {
                if (interfaces == null) {
                    interfaces = new HashSet (0);

                    if (getCachedClass().isInterface())
                      interfaces.add(this);

                    Class[] classes = getCachedClass().getInterfaces();
                    for (int i = 0; i < classes.length; i++) {
                        final CachedClass aClass = ReflectionCache.getCachedClass(classes[i]);
                        if (!interfaces.contains(aClass))
                          interfaces.addAll(aClass.getInterfaces());
                    }

                    final CachedClass superClass = getCachedSuperClass();
                    if (superClass != null)
                      interfaces.addAll(superClass.getInterfaces());
                }
                return interfaces;
            }


        --- ReflectionCache.java:276 ---

                    CachedClass fasterCachedClass = null;

                    // Double-check put.
                    synchronized (CACHED_CLASS_MAP) {
                        ref = (SoftReference) CACHED_CLASS_MAP.get(klazz);

                        if (ref == null || (fasterCachedClass = (CachedClass) ref.get()) == null) {
                            CACHED_CLASS_MAP.put(klazz, new SoftReference(cachedClass));
                        } else {
                            // We must use the one that there first, we should be able to safely toss the one we made.
                            // By locking Class we would eliminate this race, but until the design is corrected we risk
                            // deadlock.
                            cachedClass = fasterCachedClass;
                        }
                    }

                    if (null == fasterCachedClass) {
                        // We've got a new CacheClass, now get loaded into the assignableMap.
                     cachedClass.initialize();
                    }
        {code}
        If getInterfaces() is called from another thread, before CachedClass has been initialized, an exception maybe thrown. CachedClass should be put into the shared CACHED_CLASS_MAP *after* it has been initialized and not before. The initialize block may need to be synchronized to prevent a possible race condition.
        {code}
        java.util.ConcurrentModificationException
                at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
                at java.util.HashMap$KeyIterator.next(HashMap.java:828)
                at java.util.AbstractCollection.addAll(AbstractCollection.java:305)
                at org.codehaus.groovy.reflection.CachedClass.getInterfaces(CachedClass.java:70)
                at org.codehaus.groovy.reflection.CachedClass.initialize(CachedClass.java:134)
                at org.codehaus.groovy.reflection.ReflectionCache.getCachedClass(ReflectionCache.java:276)
                at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getGlobalMetaClass(MetaClassRegistryImpl.java:250)
                at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.access$100(MetaClassRegistryImpl.java:45)
                at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl$LocallyKnownClasses.getFromGlobal(MetaClassRegistryImpl.java:112)
                at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl$LocallyKnownClasses.getMetaClass(MetaClassRegistryImpl.java:88)
                at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl$MyThreadLocal.getMetaClass(MetaClassRegistryImpl.java:361)
                at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getMetaClass(MetaClassRegistryImpl.java:265)
                at org.codehaus.groovy.runtime.InvokerHelper.getProperty(InvokerHelper.java:178)
                at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.getProperty(ScriptBytecodeAdapter.java:477)
        {code}
        --- CachedClass.java:70 ---
        {code}
            private Set interfaces;

            public Set getInterfaces() {
                if (interfaces == null) {
                    interfaces = new HashSet (0);

                    if (getCachedClass().isInterface())
                      interfaces.add(this);

                    Class[] classes = getCachedClass().getInterfaces();
                    for (int i = 0; i < classes.length; i++) {
                        final CachedClass aClass = ReflectionCache.getCachedClass(classes[i]);
                        if (!interfaces.contains(aClass))
                          interfaces.addAll(aClass.getInterfaces());
                    }

                    final CachedClass superClass = getCachedSuperClass();
                    if (superClass != null)
                      interfaces.addAll(superClass.getInterfaces());
                }
                return interfaces;
            }
        {code}
        --- ReflectionCache.java:276 ---
        {code}
                    CachedClass fasterCachedClass = null;

                    // Double-check put.
                    synchronized (CACHED_CLASS_MAP) {
                        ref = (SoftReference) CACHED_CLASS_MAP.get(klazz);

                        if (ref == null || (fasterCachedClass = (CachedClass) ref.get()) == null) {
                            CACHED_CLASS_MAP.put(klazz, new SoftReference(cachedClass));
                        } else {
                            // We must use the one that there first, we should be able to safely toss the one we made.
                            // By locking Class we would eliminate this race, but until the design is corrected we risk
                            // deadlock.
                            cachedClass = fasterCachedClass;
                        }
                    }

                    if (null == fasterCachedClass) {
                        // We've got a new CacheClass, now get loaded into the assignableMap.
                     cachedClass.initialize();
                    }
        {code}
        Hide
        Guillaume Delcroix added a comment -

        The code base has changed since back then, and we've not been able to reproduce the problem.
        Please open a new issue with a reproducable case, if ever you still encounter that issue.

        Show
        Guillaume Delcroix added a comment - The code base has changed since back then, and we've not been able to reproduce the problem. Please open a new issue with a reproducable case, if ever you still encounter that issue.
        Guillaume Delcroix made changes -
        Assignee Guillaume Laforge [ guillaume ]
        Resolution Cannot Reproduce [ 5 ]
        Status Open [ 1 ] Closed [ 6 ]
        Fix Version/s 1.7.x [ 15538 ]
        Mark Thomas made changes -
        Project Import Sun Apr 05 13:32:57 UTC 2015 [ 1428240777691 ]
        Mark Thomas made changes -
        Workflow jira [ 12731972 ] Default workflow, editable Closed status [ 12743848 ]
        Mark Thomas made changes -
        Project Import Mon Apr 06 02:11:23 UTC 2015 [ 1428286283443 ]
        Mark Thomas made changes -
        Workflow jira [ 12973455 ] Default workflow, editable Closed status [ 12980685 ]
        Transition Time In Source Status Execution Times Last Executer Last Execution Date
        Open Open Closed Closed
        944d 3h 11m 1 Guillaume Delcroix 17/Feb/11 09:28

          People

          • Assignee:
            Guillaume Delcroix
            Reporter:
            James Leigh
          • Votes:
            1 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development