Skip to content

refactor: convert grails-common, grails-beans-dsl and grails-async-core to Groovy - #16577

Open
borinquenkid wants to merge 32 commits into
refactor/java-to-groovy-build-tooling-2from
refactor/java-to-groovy-core-leaves
Open

borinquenkid wants to merge 32 commits into
refactor/java-to-groovy-build-tooling-2from
refactor/java-to-groovy-core-leaves

Conversation

@borinquenkid

@borinquenkid borinquenkid commented Oct 10, 2026 •

Copy link
Copy Markdown
Member

What

Converts the remaining Java sources of grails-common, grails-beans-dsl, grails-async-core to Groovy: 10 .java files removed, 12 .groovy files added (12 files changed, 1915 insertions(+), 1780 deletions(-)).

Why

The maintainers asked on #16351 for the Java-to-Groovy migration to land one Gradle project at a time as a stack of PRs, bottom-up in dependency order. #16572 did grails-data-hibernate7; this PR is 2 of 30 in the next stack (base: 10.0.x; the branch carries the build-tooling conversion of #16576, which is closed and comes back as a rebuilt pull request, so the commits of that conversion show in this diff until it lands). The end state of every file is taken from the 9.0.x-java-to-groovy branch, which already carries the regression fixes found by CI.

Commits:

  • fa16eae refactor: convert grails-async-core to Groovy
  • 46244a7 refactor: convert grails-beans-dsl to Groovy
  • a3f34e4 refactor: convert grails-common to Groovy

Changed outside the converted sources

  • nothing

Java-facing API sweep

Every deleted .java was compared with its Groovy twin via javap -v -protected (class declaration, public/protected fields, constructors, methods incl. modifiers/throws/generics, interface default methods, nested class modifiers, and the annotations callers see). Result:

  • not applicable: these are separate Gradle builds (build-logic, grails-gradle) with no Java-facing consumers outside their own build; the consuming plugins compile

See also the notes below.

Verification

  • classes and testClasses (plus ast/cli/testFixtures source sets where present) of the converted project(s) and of their direct dependents compile: ['grails-async', 'grails-async-gpars', 'grails-async-rxjava', 'grails-async-rxjava2', 'grails-async-rxjava3', 'grails-core', 'grails-data-mongodb-core', 'grails-databinding-core', 'grails-datamapping-async', 'grails-datastore-async', 'grails-datastore-core', 'grails-domain-class', 'grails-redis', 'grails-rest-transforms', 'grails-views-core', 'grails-views-gson', 'grails-web-databinding']
  • No test suites were run locally (the umbrella branch was verified; CI runs them). codeStyle, rat and a whole-repo build -PskipTests are run once on the tip of the stack.

Notes

  • Informational sweep entries that are not regressions: Groovy enums gain MIN_VALUE/MAX_VALUE/next()/previous(), property accessors appear for formerly package-private members, nested static classes with implicit constructors become public (they were protected), and generic type parameters that Groovy erases in constructors/methods (descriptors identical).
  • Groovy gotchas that applied (see build: migrate remaining Java sources to Groovy #16351): static final without public creates a property; == calls equals(); Closure/SAM coercions; @CompileStatic with nested classes. All CI regression fixes found on the umbrella branch are included in the end state.

🤖 Generated with Claude Code

borinquenkid and others added 4 commits October 10, 2026 12:01
…l to Groovy

Converts the remaining Java sources of build-logic/docs-core, grails-gradle/common and grails-gradle/model to Groovy.
Part of the per-project split requested by the maintainers on #16351; end state taken from the
9.0.x-java-to-groovy branch (origin/9.0.x..e55fd9e).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Converts the Java sources of grails-common to Groovy.
Part of the per-project split requested by the maintainers on #16351; end state taken from the
9.0.x-java-to-groovy branch (origin/9.0.x..e55fd9e).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Converts the Java sources of grails-beans-dsl to Groovy.
Part of the per-project split requested by the maintainers on #16351; end state taken from the
9.0.x-java-to-groovy branch (origin/9.0.x..e55fd9e).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Converts the Java sources of grails-async-core to Groovy.
Part of the per-project split requested by the maintainers on #16351; end state taken from the
9.0.x-java-to-groovy branch (origin/9.0.x..e55fd9e).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@borinquenkid
borinquenkid requested review from jamesfredley and jdaugherty and a balanced review from Copilot October 10, 2026 19:58

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@codecov

codecov Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.53112% with 18 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.0887%. Comparing base (0725501) to head (98e5136).

Files with missing lines Patch % Lines
...g/apache/grails/common/aot/RegistrableTypes.groovy 84.7458% 2 Missing and 7 partials ⚠️
...nsform/internal/DelegateAsyncTransformation.groovy 96.1039% 0 Missing and 3 partials ⚠️
...pache/grails/common/reflect/ReflectionUtils.groovy 89.2857% 3 Missing ⚠️
...mpiler/beans/AutoConfigurationImportsWriter.groovy 96.4286% 0 Missing and 2 partials ⚠️
.../grails/compiler/beans/OnGrailsEnvCondition.groovy 95.0000% 0 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@                               Coverage Diff                               @@
##             refactor/java-to-groovy-build-tooling     #16577        +/-   ##
===============================================================================
- Coverage                                  64.0971%   64.0887%   -0.0084%     
- Complexity                                   28681      29082       +401     
===============================================================================
  Files                                         2260       2259         -1     
  Lines                                       112147     112015       -132     
  Branches                                     20366      20362         -4     
===============================================================================
- Hits                                         71883      71789        -94     
+ Misses                                       31140      31031       -109     
- Partials                                      9124       9195        +71     
Files with missing lines Coverage Δ
...compiler/beans/GrailsBeansASTTransformation.groovy 79.0234% <ø> (ø)
...che/grails/common/aot/AheadOfTimeProcessing.groovy 33.3333% <100.0000%> (ø)
.../grails/compiler/beans/OnGrailsEnvCondition.groovy 96.1538% <95.0000%> (ø)
...mpiler/beans/AutoConfigurationImportsWriter.groovy 93.5897% <96.4286%> (ø)
...nsform/internal/DelegateAsyncTransformation.groovy 92.8571% <96.1039%> (ø)
...pache/grails/common/reflect/ReflectionUtils.groovy 82.0513% <89.2857%> (ø)
...g/apache/grails/common/aot/RegistrableTypes.groovy 86.3636% <84.7458%> (ø)

... and 6 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@borinquenkid borinquenkid added this to the grails:9.0.0-M1 milestone Oct 11, 2026
borinquenkid and others added 4 commits October 13, 2026 06:03
…nd fix ClassPathResource.equals

- add specs for GrailsNameUtils, DefaultCommandLine and the file-resolving resources
  (file, jar and http), and extend the parser, loader, resource-utils and IO-utils specs
- ClassPathResource.equals read the other resource's classLoader through its getter,
  which falls back to the class's loader, while reading its own field; two resources
  created from the same class were therefore never equal. Compare fields on both sides,
  as the Java original did.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@rambleraptor

Copy link
Copy Markdown

Hello! Please be careful with sending out multiple PRs at once and avoid doing it when possible. This repository uses a shared set of GitHub Action runners. Currently, jobs across the entire Apache organization are being queued / timing out because these PRs are taking up most of the runners.

borinquenkid and others added 4 commits October 15, 2026 21:46
…erve rename history

git's default 50% rename-similarity threshold is what GitHub's PR view and
'git log --follow'/'blame' use to link a converted file back to its original
.java predecessor. DefaultCommandLine's full idiomatic conversion landed at
41% similarity (confirmed: GitHub shows delete+add, not a rename, losing
file history per matrei's review comment on #16576).

This keeps the method-body semicolons (76% similarity, confirmed rename-
detected, confirmed git log --follow/blame trace through to the real
pre-conversion commits and author) while still applying every other idiom
fix: dropped the public modifier, the 7 unnecessary java.util.* imports,
and the 4 non-interpolated double-quoted string literals CodeNarc also
flags. @SuppressWarnings('UnnecessarySemicolon') marks this as a known,
temporary, scoped exception pending the stacked groovyism-cleanup PR, which
removes both the semicolons and this suppression.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
borinquenkid and others added 6 commits October 17, 2026 21:16
…ning

GlobalGrailsClassInjectorTransformationSpec's "a generated class missing from
a hand-authored imports file is reported" fails on every GitHub-hosted runner
(Ubuntu 21/25, macOS, Windows, Coverage) with an empty warning list, and
passes locally in isolation, paired with every other base.dir-touching spec,
and in the full suite at both local and CI fork counts. Static analysis rules
out base.dir leakage (grails-core ships its own hand-authored imports file,
so a leaked value would still warn), groovy.* property mutation, Spock
parallelism and Groovy version drift (6.0.0 pinned on both sides).

This inlines the compilation so the power assertion prints which branch of
AutoConfigurationImportsWriter.register ran on the runner: whether the sibling
was generated, whether the generated imports file was written (hand-authored
file not found) or not (hand-authored branch taken), the collector's warning
level and counts, and the directories involved.

REVERT THIS COMMIT once the CI log has been read.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…by the rename-fix

580bd5e rebuilt DefaultCommandLine from the .java original, which carries
no annotations, and so lost the @CompileStatic stage 1 had put on the class
and the @PackageScope on systemProperties, undeclaredOptions, declaredOptions
and remainingArgs. Without them the four fields became public Groovy
properties with generated accessors and the class fell back to dynamic
dispatch. Both are restored; similarity stays at R069.

grails-gradle-model: compile, codenarc and 432 tests pass.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Conflicts: GrailsResourceUtils.groovy takes upstream's getPathFromRoot change
(18d8daf); the four grails-gradle/model specs upstream added in 186b59c
with the same names as this branch's are kept verbatim, with the nine feature
methods only this branch's versions asserted appended.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…stem interaction specs

Backport of #16664 (ff463cc on 7.2.x, merged up to 9.0.x) to the three
10.0.x copies of the spec, so the Windows shards pass until the 9.0.x merge-up
reaches 10.0.x; the lines are identical, so that merge stays clean.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
borinquenkid and others added 2 commits October 18, 2026 10:15
…10.0.x

10.0.x was branched from 9.1.x without the version bump, so gradle.properties
still said projectVersion=9.1.0-SNAPSHOT and githubBranch=9.1.x. The
'Validate githubBranch' job therefore fails on every pull request whose base
is 10.0.x. Same four files as the 9.1.x bump in 829de60.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit fb8ecf0)
@borinquenkid
borinquenkid marked this pull request as draft October 19, 2026 21:01
…move before merge)

Keeps CI on the stacked Java-to-Groovy PRs cheap while the chain is reviewed and rebased. The PR closest
to the release branch keeps the full build; this block is dropped from a PR when its base is merged.
Merging with this commit is a blocker.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@borinquenkid
borinquenkid marked this pull request as ready for review October 19, 2026 21:20
@borinquenkid

borinquenkid commented Oct 19, 2026 •

Copy link
Copy Markdown
Member Author

SUPERSEDED: the skipTests/skipCodeStyle flag described below was removed. See the newer comment about the CHANGEME FOR ACCEPTANCE workflow-trigger commit, which is the only temporary CI change on this branch.

Temporary CI flag on this stacked branch (BLOCKER before merge).

This Java-to-Groovy chain is a stack of PRs, and every push to any of them starts the full CI matrix, which is more runner time than the ASF allows us. Every PR in the stack except the one closest to its release branch (#16576) therefore carries one temporary commit, CHANGEME FOR ACCEPTANCE, that adds this to the root gradle.properties:

skipTests=true
skipCodeStyle=true

With it, CI on this PR compiles but does not run tests or code style. The full build runs on #16576 (closest to 10.0.x), and each PR gets it when the PR below it has merged.

Condition for merging this PR: that gradle.properties block (and the CHANGEME FOR ACCEPTANCE commit) must be dropped from this branch first, and CI must then be green with the tests running. A green check on this PR as it stands does not mean the tests ran. Rollout of the commit is branch by branch, so a branch may not carry it yet.

…(revert before merge)

The skipTests/skipCodeStyle flag only removed test execution; the functional jobs still compiled the whole
repository (~57 minutes each) on every push. Turn the pull_request triggers into a branch filter that never
matches so pushes, rebases and force-pushes to the stacked PRs start no jobs. Reverts the gradle.properties flag.
The PR closest to the release branch keeps its triggers. Merging with this commit is a blocker.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@borinquenkid

Copy link
Copy Markdown
Member Author

Update: this branch now carries a different temporary CI commit (BLOCKER before merge).

The earlier skipTests/skipCodeStyle flag in gradle.properties did not help enough: the functional jobs still compile the whole repository (about 57 minutes each) on every push, so it only saved around a fifth of the time. It has been removed.

In its place, every PR in this stack except #16576 (the one closest to 10.0.x) carries one temporary commit, CHANGEME FOR ACCEPTANCE: disable PR workflow triggers. It changes the pull_request: trigger of each workflow to branches: ['CHANGEME-FOR-ACCEPTANCE'], a branch that does not exist, so pushing, rebasing or force-pushing this branch starts no jobs.

Condition for merging this PR: that commit must be reverted on this branch first (git revert of the CHANGEME FOR ACCEPTANCE commit), and CI must then run and be green. The absence of CI checks on this PR is deliberate and does not mean the code was tested. The full build runs on #16576, and each PR gets it when the PR below it has merged.

…va-to-groovy-core-leaves

# Conflicts:
#	.github/workflows/benchmark.yml
#	.github/workflows/build-health.yml
#	.github/workflows/codeanalysis.yml
#	.github/workflows/codeql.yml
#	.github/workflows/codestyle.yml
#	.github/workflows/coverage.yml
#	.github/workflows/end-to-end.yml
#	.github/workflows/gradle.yml
#	.github/workflows/groovy-snapshot-canary.yml
#	.github/workflows/rat.yml
#	.github/workflows/sitemesh2.yml
#	.github/workflows/validate-actions.yml
#	.github/workflows/vulnerability-scan.yml
@borinquenkid
borinquenkid changed the base branch from refactor/java-to-groovy-build-tooling to 10.0.x October 23, 2026 20:53
…va-to-groovy-core-leaves

The build-tooling files of this branch come from the one-commit conversion of #16576, which is replaced by a conversion that moves
the files first and converts them in a second commit. The new content of the three projects replaces the old one; nothing else changes.

Claude-Session: https://claude.ai/code/session_01MDHn7fC3hsGJ27vFHD2o1p
@borinquenkid
borinquenkid changed the base branch from 10.0.x to refactor/java-to-groovy-build-tooling-2 October 23, 2026 21:35
@testlens-app

testlens-app Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

🔎 No tests executed 🔎

🏷️ Commit: 72d70ad
▶️ Tests: 0 executed
⚪️ Checks: 46/46 completed


Learn more about TestLens at testlens.app/docs.

This branch has not been deployed

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

Labels

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

4 participants