Skip to content

Migrate to Groovy 4 which supports Java 25#732

Open
JonasPBovin wants to merge 2 commits intojenkinsci:masterfrom
JonasPBovin:use-groovy4-to-enable-java25
Open

Migrate to Groovy 4 which supports Java 25#732
JonasPBovin wants to merge 2 commits intojenkinsci:masterfrom
JonasPBovin:use-groovy4-to-enable-java25

Conversation

@JonasPBovin
Copy link

Migrated test framework to Groovy 4 (required for Java 25 compatibility).

These changes are an absolute minimum to get the majority of the functionality to work under Java 25 - I ran into the following challenges:

  • Map.toString() was changed in Groovy 4 so changes to the bottom files are generally only that
  • I could not figure out how to get the classes instantiated from within a loaded script to be instrumented with methodMissing (help to add to this PR would be greatly appreciated)
  • Lot's of hard to find subtle changes that should be persisted since it took time to find them

During the upgrade, several cross-class shared library interoperability tests started failing with MissingMethodException (e.g. pipeline step sh not intercepted inside library class instances). These tests are now temporarily ignored pending a redesign of interception logic under Groovy 4.

Ignored tests in src/test/groovy/com/lesfurets/jenkins/TestInterceptingGCL.groovy:

  • test_cross_class_interop_library_loaded_with_implicit
  • test_cross_class_interop_no_implicit_dynamic
  • test_cross_class_interop_no_implicit_annotation
  • test_pre_loaded_cross_class_interop_library_loaded_with_implicit
  • test_pre_loaded_cross_class_interop_no_implicit_dynamic
  • test_pre_loaded_cross_class_interop_no_implicit_annotation

Reason: Cross class interoperability with @Library annotation not yet supported under Groovy 4; pipeline step interception differs from Groovy 2.x/3.x causing MissingMethodException (example: ClassA.sh(echo 'ClassA: I'm field of A')).

Next steps (not in this commit):

  • Investigate adapting PipelineTestHelper.callMethod for method dispatch inside library class instances.
  • Re-enable tests once interception restored.

Refs:

Testing done

JUnit test ran in IDE, maven and gradle - library depending on this library ran in Java 25

Submitter checklist

  • Make sure you are opening from a topic/feature/bugfix branch (right side) and not your main branch!
  • Ensure that the pull request title represents the desired changelog entry
  • Please describe what you did
  • Link to relevant issues in GitHub or Jira
  • Link to relevant pull requests, esp. upstream and downstream changes
  • Ensure you have provided tests that demonstrate the feature works or the issue is fixed

Migrated test framework to Groovy 4 (required for Java 25 compatibility). During the upgrade, several cross-class shared library interoperability tests started failing with MissingMethodException (e.g. pipeline step `sh` not intercepted inside library class instances). These tests are now temporarily ignored pending a redesign of interception logic under Groovy 4.

Ignored tests in `src/test/groovy/com/lesfurets/jenkins/TestInterceptingGCL.groovy`:
- test_cross_class_interop_library_loaded_with_implicit
- test_cross_class_interop_no_implicit_dynamic
- test_cross_class_interop_no_implicit_annotation
- test_pre_loaded_cross_class_interop_library_loaded_with_implicit
- test_pre_loaded_cross_class_interop_no_implicit_dynamic
- test_pre_loaded_cross_class_interop_no_implicit_annotation

Reason: Cross class interoperability with @Library annotation not yet supported under Groovy 4; pipeline step interception differs from Groovy 2.x/3.x causing `MissingMethodException` (example: `ClassA.sh(echo 'ClassA: I'm field of A')`).

Next steps (not in this commit):
- Investigate adapting `PipelineTestHelper.callMethod` for method dispatch inside library class instances.
- Re-enable tests once interception restored.

Refs: branch `use-groovy4-to-enable-java25`
@JonasPBovin JonasPBovin changed the title Migrate to Groovy 4 which support Java 25 Migrate to Groovy 4 which supports Java 25 Oct 17, 2025
* @param args method arguments
*/
protected void registerMethodCall(Object target, int stackDepth, String name, Object... args) {
if (name.equalsIgnoreCase('getBinding')) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These suddenly filled the stack output

Script loadInlineScript(String scriptText, Binding binding) {
Objects.requireNonNull(binding, "Binding cannot be null.")
Objects.requireNonNull(gse, "GroovyScriptEngine is not initialized: Initialize the helper by calling init().")
GroovyShell shell = new GroovyShell(gse.getParentClassLoader(), binding, gse.getConfig())
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The load inline was completely broken, it was just hanging - so used existing logic to treat as file scripts

.filter ({File it -> it.name.endsWith('.groovy') } as Predicate<File>)
.map { FilenameUtils.getBaseName(it.name) }
.filter ({String it -> !globalVars.containsValue(it) } as Predicate<String>)
.filter ({String it -> !globalVars.containsKey(it) } as Predicate<String>)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed for upgrade, but was clearly an error

// declare componentInstance as final to prevent any multithreaded issues, since it is used inside closure
final def componentInstance = componentType.newInstance()
def rehydrate = closure.rehydrate(componentInstance, closure, componentInstance)
rehydrate.resolveStrategy = DELEGATE_FIRST
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Helped with the majority of the issues of switching...

@nre-ableton
Copy link
Contributor

Jenkins itself only supports Groovy 2, although there is a long-standing effort underway to support Groovy 3/4, see https://community.jenkins.io/t/upgrade-groovy-jenkins-plugin/6892 (for example).

I worry that supporting Groovy 4 would allow for developers mistakenly adding Groovy 4 features in their pipeline libraries, which would work fine when tested with this framework, but not on an actual Jenkins instance.

@JonasPBovin
Copy link
Author

I worry that supporting Groovy 4 would allow for developers mistakenly adding Groovy 4 features in their pipeline libraries, which would work fine when tested with this framework, but not on an actual Jenkins instance.

First of all, thanks for taking the time to comment. I share your concern - maybe it could be addressed? But as it stands we cannot build nor test our extensive java/groovy jenkins shared library when everything is moved to java 25. As long as groovy 2 does not provide a version that can recognise java 25 classfiles, this is our only course of action.

@nre-ableton
Copy link
Contributor

I worry that supporting Groovy 4 would allow for developers mistakenly adding Groovy 4 features in their pipeline libraries, which would work fine when tested with this framework, but not on an actual Jenkins instance.

First of all, thanks for taking the time to comment. I share your concern - maybe it could be addressed? But as it stands we cannot build nor test our extensive java/groovy jenkins shared library when everything is moved to java 25. As long as groovy 2 does not provide a version that can recognise java 25 classfiles, this is our only course of action.

Yeah, I share your frustration. We're kind of stuck in the middle here: needing to support an older Groovy version and a newer Java version. Also, it's worth noting that Jenkins itself doesn't have Java 25 support, and this isn't in the roadmap yet: https://www.jenkins.io/doc/book/platform-information/support-policy-java/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants