You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@groovy.apache.org by "Paul King (Jira)" <ji...@apache.org> on 2026/07/14 01:10:00 UTC
[jira] [Resolved] (GROOVY-12149) Nondeterministic reflection order flows into generated bytecode, breaking reproducible builds
[ https://issues.apache.org/jira/browse/GROOVY-12149?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Paul King resolved GROOVY-12149.
--------------------------------
Fix Version/s: 5.0.8
6.0.0-beta-1
Assignee: Paul King
Resolution: Fixed
> Nondeterministic reflection order flows into generated bytecode, breaking reproducible builds
> ---------------------------------------------------------------------------------------------
>
> Key: GROOVY-12149
> URL: https://issues.apache.org/jira/browse/GROOVY-12149
> Project: Groovy
> Issue Type: Bug
> Reporter: James Daugherty
> Assignee: Paul King
> Priority: Major
> Fix For: 5.0.8, 6.0.0-beta-1
>
>
> Follow-up to GROOVY-12146, which fixed nondeterministic ordering of annotation members copied from precompiled classes. The same root cause — Class.getDeclaredMethods()/getDeclaredFields()/getDeclaredConstructors() returning members in an unspecified order that varies between HotSpot runs — also affects Java8#configureClassNode, which populates ClassNodes for precompiled classes via reflection. The enumeration order is preserved through to bytecode generation (e.g. via the LinkedHashMap returned by ClassNode#getDeclaredMethodsMap), so two compilations of identical sources on the same JDK can still produce byte-different class files.
> Two manifestations were observed while verifying the reproducibility of the Apache Grails 8.0.0-M3 release artifacts (same sources, same JDK, containerized double-build):
> 1. MOP bridge methods: for classes extending a precompiled Groovy class, MopWriter#getSuperMethods iterates the superclass's declared-methods map, so the synthetic super$N$… methods are emitted in a different order per build.
> 2. Woven trait methods: methods copied from a precompiled trait (e.g. GORM's DirtyCheckable#trackChanges/syncChangedProperties) are woven into implementing classes in enumeration order, reordering the emitted methods and the constant pool.
> In both cases the bytecode is semantically identical — decompiled sources match exactly — only member emission order (and the constant-pool layout that follows from it) differs.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)