[ 
https://issues.apache.org/jira/browse/GROOVY-12580?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Scott Murphy Heiberg updated GROOVY-12580:
------------------------------------------
    Description: 
{{ClassInfo.remove(Class)}} drops the class's association, and the next use of 
the class creates a new {{ClassInfo}}. The default Groovy methods and extension 
methods of a class are written into its {{ClassInfo}} once, by the registry at 
startup, so the class loses them for the rest of the runtime's life:

{code:groovy}
import org.codehaus.groovy.reflection.ClassInfo
ClassInfo.remove(StringBuilder)
def sb = new StringBuilder('ab')
sb[0..0] = 'z' // MissingMethodException: No signature of method: putAt for 
class: java.lang.StringBuilder
{code}

{{sb << 'x'}} falls back to {{CharSequence.leftShift}}, which returns a new 
builder and leaves {{sb}} empty, or to {{Appendable.leftShift}}, depending on 
hash order. After the sweep the integration guide documents for application 
shutdown, a runtime still in use loses every default Groovy method:

{code:groovy}
import org.codehaus.groovy.reflection.ClassInfo
for (ClassInfo ci : ClassInfo.getAllClassInfo()) { Class<?> c = 
ci.getTheClass(); if (c != null) ClassInfo.remove(c) }
[1, 2, 3].collect { it * 2 } // MissingMethodException: No signature of method: 
multiply for class: java.lang.Integer
{code}

{{bugs.Groovy12142.testClassInfoRemoveSweepIsSafeToRunRepeatedly}} removes the 
{{ClassInfo}} of {{StringBuilder}}, so {{bugs.Groovy12363}}, whose anonymous 
class does {{sink << who}}, fails when it runs later in the same test JVM.

The guide's sweep, written as dynamic Groovy and run by the copy it cleans up, 
also keeps that copy's class loader reachable, since a dynamic call made after 
the first removal associates a class with that runtime again.

PR: https://github.com/apache/groovy/pull/3096

  was:
{{ClassInfo.remove(Class)}} drops the class's association, and the next use of 
the class creates a new {{ClassInfo}}. The default Groovy methods and extension 
methods of a class are written into its {{ClassInfo}} once, by the registry at 
startup, so the class loses them for the rest of the runtime's life:

{code:groovy}
import org.codehaus.groovy.reflection.ClassInfo
ClassInfo.remove(StringBuilder)
def sb = new StringBuilder('ab')
sb[0..0] = 'z' // MissingMethodException: No signature of method: putAt for 
class: java.lang.StringBuilder
{code}

{{sb << 'x'}} falls back to {{CharSequence.leftShift}}, which returns a new 
builder and leaves {{sb}} empty, or to {{Appendable.leftShift}}, depending on 
hash order. After the sweep the integration guide documents for application 
shutdown, a runtime still in use loses every default Groovy method:

{code:groovy}
import org.codehaus.groovy.reflection.ClassInfo
for (ClassInfo ci : ClassInfo.getAllClassInfo()) { Class<?> c = 
ci.getTheClass(); if (c != null) ClassInfo.remove(c) }
[1, 2, 3].collect { it * 2 } // MissingMethodException: No signature of method: 
multiply for class: java.lang.Integer
{code}

{{bugs.Groovy12142.testClassInfoRemoveSweepIsSafeToRunRepeatedly}} removes the 
{{ClassInfo}} of {{StringBuilder}}, so {{bugs.Groovy12363}}, whose anonymous 
class does {{sink << who}}, fails when it runs later in the same test JVM.

The guide's sweep, written as dynamic Groovy and run by the copy it cleans up, 
also keeps that copy's class loader reachable, since a dynamic call made after 
the first removal associates a class with that runtime again.


> ClassInfo.remove takes a class's default Groovy methods with it
> ---------------------------------------------------------------
>
>                 Key: GROOVY-12580
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12580
>             Project: Groovy
>          Issue Type: Bug
>          Components: groovy-runtime
>    Affects Versions: 4.0.33, 5.0.8, 6.0.0
>            Reporter: Scott Murphy Heiberg
>            Priority: Major
>
> {{ClassInfo.remove(Class)}} drops the class's association, and the next use 
> of the class creates a new {{ClassInfo}}. The default Groovy methods and 
> extension methods of a class are written into its {{ClassInfo}} once, by the 
> registry at startup, so the class loses them for the rest of the runtime's 
> life:
> {code:groovy}
> import org.codehaus.groovy.reflection.ClassInfo
> ClassInfo.remove(StringBuilder)
> def sb = new StringBuilder('ab')
> sb[0..0] = 'z' // MissingMethodException: No signature of method: putAt for 
> class: java.lang.StringBuilder
> {code}
> {{sb << 'x'}} falls back to {{CharSequence.leftShift}}, which returns a new 
> builder and leaves {{sb}} empty, or to {{Appendable.leftShift}}, depending on 
> hash order. After the sweep the integration guide documents for application 
> shutdown, a runtime still in use loses every default Groovy method:
> {code:groovy}
> import org.codehaus.groovy.reflection.ClassInfo
> for (ClassInfo ci : ClassInfo.getAllClassInfo()) { Class<?> c = 
> ci.getTheClass(); if (c != null) ClassInfo.remove(c) }
> [1, 2, 3].collect { it * 2 } // MissingMethodException: No signature of 
> method: multiply for class: java.lang.Integer
> {code}
> {{bugs.Groovy12142.testClassInfoRemoveSweepIsSafeToRunRepeatedly}} removes 
> the {{ClassInfo}} of {{StringBuilder}}, so {{bugs.Groovy12363}}, whose 
> anonymous class does {{sink << who}}, fails when it runs later in the same 
> test JVM.
> The guide's sweep, written as dynamic Groovy and run by the copy it cleans 
> up, also keeps that copy's class loader reachable, since a dynamic call made 
> after the first removal associates a class with that runtime again.
> PR: https://github.com/apache/groovy/pull/3096



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to