[ 
https://issues.apache.org/jira/browse/GROOVY-12580?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18135261#comment-18135261
 ] 

ASF GitHub Bot commented on GROOVY-12580:
-----------------------------------------

codeconsole commented on PR #3096:
URL: https://github.com/apache/groovy/pull/3096#issuecomment-6526833129

   
   @daniellansun thanks.
   
   1. Fixed in 79028a0926. `java.lang.ClassValue`, the default store, has no 
get-if-present, so `ClassInfo` keeps the lookup itself: the global set now also 
indexes its `ClassInfo`s by class, keys and values held weakly, and that index 
replaces the map of detached instances. `ClassInfo.remove` looks the instance 
up there and never creates one; a class without a `ClassInfo` is left without 
one. `computeValue` gets a still reachable (detached) instance back from the 
same index, as before. 
`Groovy12142.testRemovingAClassWithoutClassInfoCreatesNone` checks it through 
`ClassInfo.getAllClassInfo()` and fails on the previous `ClassInfo.remove`. The 
set's queue stays as it is because Gradle's 
`ClassInfoCleaningGroovySystemLoader` reads it reflectively.
   2. The put is gone. The instance stays in the index from creation, so 
`remove` only clears the MetaClasses under the `ClassInfo` lock and then drops 
the association. A `get` before the drop sees the association; one after it 
gets the same instance back from the index.
   3. #3096 is stacked on #3095 and already contains it (merged with master). 
#3095 should merge first; #3096 then shows only its own GROOVY-12580 commits.
   
   The `lts (17, windows-latest, 1)` timeout is the same 60m Gradle step 
timeout as on #3095. `bugs.Groovy12142` and `bugs.Groovy12363` pass locally on 
JDK 17.0.20.
   
   




> 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