groovy
  1. groovy
  2. GROOVY-5198

using "as" to coerce a String to an Enum value results in a groovy.lang.MissingMethodException under high contention

    Details

    • Type: Bug Bug
    • Status: Closed Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 1.8.4
    • Fix Version/s: 1.8.5, 2.0-beta-2, 1.7.11
    • Component/s: None
    • Labels:
      None
    • Environment:
      OS X lion w/ JDK1.6.0_29 (build 1.6.0_29-b11-402-11M3527)
    • Number of attachments :
      1

      Description

      I've provided a test case in the form of a simple script that can be run in GroovyConsole.

      It creates 5000 threads – each thread converts strings to enums in a loop.
      I tried three different methods of converting strings to Enums in the test.

      These two seem to work fine:

      Foo f = Foo.valueOf(key)
      Foo f = Enum.valueOf(Foo, key)

      However, under load, this method:

      Foo f = key as Foo

      will occasionally throw an exception like the following:

      Exception in thread "Thread-127349" 
      org.codehaus.groovy.runtime.InvokerInvocationException: groovy.lang.MissingMethodException: No signature of method: static Foo.valueOf() is applicable for argument types: (java.lang.String) values: [bar]
      Possible solutions: valueOf(java.lang.String), valueOf(java.lang.Class, java.lang.String), values()
      	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:97)
      	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
      	at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:272)
      	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:883)
      	at groovy.lang.Closure.call(Closure.java:410)
      	at groovy.lang.Closure.call(Closure.java:404)
      	at groovy.lang.Closure.run(Closure.java:488)
      	at java.lang.Thread.run(Thread.java:680)
      Caused by: groovy.lang.MissingMethodException: No signature of method: static Foo.valueOf() is applicable for argument types: (java.lang.String) values: [bar]
      Possible solutions: valueOf(java.lang.String), valueOf(java.lang.Class, java.lang.String), values()
      	at groovy.lang.MetaClassImpl.invokeStaticMissingMethod(MetaClassImpl.java:1349)
      	at groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1335)
      	at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:767)
      	at org.codehaus.groovy.runtime.DefaultGroovyMethods.asType(DefaultGroovyMethods.java:17327)
      	at org.codehaus.groovy.runtime.dgm$58.doMethodInvoke(Unknown Source)
      	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1053)
      	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:883)
      	at org.codehaus.groovy.runtime.InvokerHelper.invokePojoMethod(InvokerHelper.java:781)
      	at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:772)
      	at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodN(ScriptBytecodeAdapter.java:164)
      	at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.asType(ScriptBytecodeAdapter.java:587)
      	at TestCase$_run_closure1_closure4_closure5.doCall(TestCase.groovy:12)
      	at sun.reflect.GeneratedMethodAccessor682.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:90)
      	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
      	at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:272)
      	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:883)
      	at groovy.lang.Closure.call(Closure.java:410)
      	at groovy.lang.Closure.call(Closure.java:423)
      	at org.codehaus.groovy.runtime.DefaultGroovyMethods.times(DefaultGroovyMethods.java:12140)
      	at org.codehaus.groovy.runtime.dgm$753.invoke(Unknown Source)
      	at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoMetaMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:271)
      	at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:53)
      	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
      	at TestCase$_run_closure1_closure4.doCall(TestCase.groovy:10)
      	at sun.reflect.GeneratedMethodAccessor672.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:90)
      	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
      	at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:272)
      	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:883)
      	at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:66)
      	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
      	at TestCase$_run_closure1_closure4.doCall(TestCase.groovy)
      	at sun.reflect.GeneratedMethodAccessor665.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:90)
      	... 7 more
      

      It's a concurrency issue, so the test isn't 100% reliable, but on my hardware this test can make the "as" conversion fail at least once in a test run most of the time. The other two methods seem to always work.

        Activity

        CÚdric Champeau made changes -
        Field Original Value New Value
        Assignee Cedric Champeau [ melix ]
        Hide
        CÚdric Champeau added a comment -

        Fixed making CacheEntry fields final.

        Show
        CÚdric Champeau added a comment - Fixed making CacheEntry fields final.
        CÚdric Champeau made changes -
        Status Open [ 1 ] Resolved [ 5 ]
        Fix Version/s 2.0-beta-2 [ 18072 ]
        Fix Version/s 1.7.11 [ 17244 ]
        Fix Version/s 1.8.5 [ 18071 ]
        Resolution Fixed [ 1 ]
        Paul King made changes -
        Status Resolved [ 5 ] Closed [ 6 ]

          People

          • Assignee:
            CÚdric Champeau
            Reporter:
            Sean Reilly
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: