[
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)