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

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

paulk-asert opened a new pull request, #2789:
URL: https://github.com/apache/groovy/pull/2789

   … Groovy 4 compiled @Immutable classes
   
   The @Immutable transform in Groovy 4.0.5 through 4.0.x (GROOVY-10747) 
emitted references to org.apache.groovy.runtime.ObjectUtil.cloneObject into 
generated constructors and getters for defensive copies. The class was removed 
along with the $getLookup machinery it relied on (GROOVY-10931), so such 
pre-compiled classes fail on Groovy 5+ with NoClassDefFoundError at first 
instantiation — only when a clone path actually executes, which for collection 
properties depends on the runtime value being Cloneable, making the failure 
intermittent.
   
   Restore the class as a deprecated facade with the original semantics minus 
the lookup dependency: null passes through, non-Cloneables throw 
CloneNotSupportedException, arrays clone via the unchanged ArrayUtil fast 
paths, and other Cloneables clone through their public clone() via the MOP 
(guarded by the same getMethod check as the original, so a non-public clone() 
still surfaces NoSuchMethodException). Nothing compiled by Groovy 5+ references 
the class; current transforms emit indy or InvokerHelper clone calls instead.
   
   Verified against real Groovy 4.0.33 bytecode: the reproducer's List property 
shape and the unconditional array/getter shape both fail with 
NoClassDefFoundError before this change and pass with it, preserving 
defensive-copy semantics.




> Groovy 4 @Immutable bytecode fails on Groovy 5 because ObjectUtil was removed
> -----------------------------------------------------------------------------
>
>                 Key: GROOVY-12257
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12257
>             Project: Groovy
>          Issue Type: Bug
>    Affects Versions: 5.0.8
>            Reporter: Mattias Reichel
>            Priority: Major
>
> h3. Summary
> A class compiled with Groovy 4 using @Immutable fails at runtime when 
> executed with Groovy 5.
> The Groovy 4 @Immutable AST transformation generates bytecode that calls:
> {code:java}
> org.apache.groovy.runtime.ObjectUtil.cloneObject(Object)
> {code}
> org.apache.groovy.runtime.ObjectUtil is present in Groovy 4 but was removed 
> in Groovy 5. Constructing an affected class therefore throws:
> {code:java}
> java.lang.NoClassDefFoundError: org/apache/groovy/runtime/ObjectUtil
> {code}
> h3. Reproducer
> A minimal Gradle reproducer is provided here: 
> https://github.com/matrei/groovy-immutable-compat. It compiles the class with 
> Groovy 4.0.33 and runs it with Groovy 5.0.8:
> {code:groovy}
> import groovy.transform.Immutable
> @Immutable
> class ImmutableValue {
>     List<String> values
> }
> println new ImmutableValue(['value'])
> {code}
> Run:
> {code:bash}
> ./gradlew reproduce
> {code}
> h3. Actual Behaviour
> Compilation succeeds with Groovy 4, but execution with Groovy 5 fails when 
> the immutable class is instantiated:
> {code:java}
> java.lang.NoClassDefFoundError: org/apache/groovy/runtime/ObjectUtil
> {code}
> h3. Expected Behaviour
> Groovy 4-compiled @Immutable classes should remain binary-compatible with 
> Groovy 5, or the Groovy 5 transformation/runtime should provide a 
> compatibility path for the generated bytecode.
> Recompiling the source with Groovy 5 avoids the problem, but this does not 
> help users consuming libraries or plugins distributed as Groovy 4-compiled 
> binaries.
> h3. Root Cause
> The Groovy 4 @Immutable transformation emits calls to 
> ObjectUtil.cloneObject(Object) for defensive copying of properties such as 
> collections. The referenced runtime class was removed in Groovy 5:
> {code:java}
> Groovy 4: org/apache/groovy/runtime/ObjectUtil.class is present
> Groovy 5: org/apache/groovy/runtime/ObjectUtil.class is absent
> {code}
> The failure is not detected during dependency resolution or application 
> startup. It occurs only when the affected immutable class is instantiated.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to