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