Skip to content

refactor: convert build-logic docs-core and grails-gradle common/model to Groovy - #16744

Open
borinquenkid wants to merge 4 commits into
10.0.xfrom
refactor/java-to-groovy-build-tooling-2
Open

borinquenkid wants to merge 4 commits into
10.0.xfrom
refactor/java-to-groovy-build-tooling-2

Conversation

@borinquenkid

@borinquenkid borinquenkid commented Oct 23, 2026 •

Copy link
Copy Markdown
Member

Merge this pull request with a merge commit. Never squash and never rebase-merge: the history of the Java files is visible from the Groovy files only while both commits below survive.

What

Replaces #16576 and its idiom follow-up #16661. Converts the Java sources of build-logic/docs-core, grails-gradle/common and grails-gradle/model to Groovy, the way #16572 does for grails-data-hibernate7. It is the conversion and nothing else: no feature, no fix, no documentation change.

Commits, in order, on top of 94fd84675f (10.0.x), then a merge of the current 10.0.x and one fix:

Commit What
move git mv only: 20 .java files to their .groovy paths, every line R100, no content change
convert the conversion, already in Groovy style: no semicolons, single quotes, no public on members, no suppressions, @CompileStatic where there is code, plus the specs that cover the converted classes
fix (46615102eb) restores the Java-facing API that the javap diff below found changed, and the null checks of SpringIOUtils

git log --follow on any converted file reaches its Java history, including CommandLineParser and DefaultCommandLine, which a single-commit conversion falls below git's rename threshold for.

Why this replaces #16576 and #16661

#16576 converted in one commit and kept Java syntax to hold rename similarity (52% to 92%, none at 100%); #16661 then removed that syntax. With the move as its own commit that workaround is not needed, so the two collapse into one pull request that is already in the final style. matrei's request on #16576 to git move the files is what the first commit does.

Java-facing API

Checked with javap -protected over the jars built from 94fd84675f (Java) and from this branch (Groovy), class by class for the 20 converted sources. After 46615102eb the only differences are what every Groovy class carries (GroovyObject, $getLookup, __$stMC, the enum next/previous/MIN_VALUE/MAX_VALUE) and String[] parameters that are now varargs, which Java callers compile against unchanged.

What the diff found and 46615102eb restores:

  • GrailsResourceUtils.DOMAIN_PATH_PATTERN, RESOURCE_PATH_PATTERN, SPRING_SCRIPTS_PATH_PATTERN and COMPILER_ROOT_PATTERNS are public static fields in Java. Without a modifier Groovy made them properties, so a compiled Java caller reading the field would fail with NoSuchFieldError. They are declared public again.
  • CommandLineParser.ENV_ARGS, DEFAULT_ENVS and GrailsNameUtils.convertValidPropertyMethodSuffix are package-private in Java and had become public; they are @PackageScope again.
  • SpringIOUtils checked its arguments with assert, which Java skips without -ea and Groovy always runs, so a missing argument became an AssertionError. The fifteen checks are Objects.requireNonNull with the same messages: the NullPointerException a Java caller got, thrown up front. SpringIOUtilsSpec checks the exception and the message of each.

JavaCallerPin.java, compiled with the grails-gradle-model tests, pins the public fields, a constant of each kind, the constructors and the checked exceptions. Turning DOMAIN_PATH_PATTERN back into a property fails its compilation.

Remaining dynamic sites (javap -c -p over the converted classes): only Groovy's generated this$dist$* and methodMissing/propertyMissing bridges of classes with anonymous inner classes (DefaultCommandLine, DefaultResourceLoader, GrailsResourceUtils, SupplierUtil), the enum $INIT of XmlParserFeature, and $getStaticMetaClass. No converted method dispatches dynamically.

Verification

Run Result
:grails-docs-core:test 67 tests, 1 failure: FetchTagsTaskSpec runs git tag in a temporary repository and fails on a machine whose git config signs every tag (tag.gpgsign); the spec is not touched by this PR
:grails-gradle-model:test, :grails-gradle-common:test 418 and 24 tests, 0 failures (no JUnit tests before or after; all specs)
codenarcMain and codenarcTest on grails-gradle-model, codenarcMain on grails-gradle-common no violations, no suppression
tree of the convert commit against the former groovyism/build-tooling tip identical

Also run from the root: rat, validateRepositoryConventions and codeStyle, all clean.

After the conversion Checkstyle has no sources in these projects (NO-SOURCE), so CodeNarc is the analyzer that gates them.

CI ran green on 506d8458c8; 46615102eb runs under no ci until the review is done, then a full run confirms the final tree.

https://claude.ai/code/session_01MDHn7fC3hsGJ27vFHD2o1p

…el Java sources to their Groovy paths

Only the rename: 20 files, every one R100, with the Java text unchanged so that git log --follow reaches the Java history from the
Groovy files. The next commit converts them.

Claude-Session: https://claude.ai/code/session_01MDHn7fC3hsGJ27vFHD2o1p
…l to Groovy

The conversion of the 20 files moved by the previous commit, in Groovy style: no semicolons, single quotes, no public modifiers,
no suppressions, and @CompileStatic where there is code. Adds the specs that cover the converted classes and the changes the
sources needed to compile as Groovy.

Claude-Session: https://claude.ai/code/session_01MDHn7fC3hsGJ27vFHD2o1p

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 insufficient remaining quota.

@borinquenkid
borinquenkid marked this pull request as draft October 23, 2026 23:29
@borinquenkid
borinquenkid marked this pull request as ready for review October 23, 2026 23:29
@codecov

codecov Bot commented Oct 24, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.06723% with 66 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.7450%. Comparing base (506b568) to head (506d845).
⚠️ Report is 842 commits behind head on 10.0.x.

Files with missing lines Patch % Lines
...y/org/grails/io/support/GrailsResourceUtils.groovy 89.2857% 13 Missing and 11 partials ⚠️
...ovy/org/grails/io/support/ClassPathResource.groovy 77.4194% 11 Missing and 3 partials ⚠️
.../groovy/org/grails/io/support/SpringIOUtils.groovy 92.9825% 2 Missing and 6 partials ⚠️
.../org/grails/build/parsing/CommandLineParser.groovy 95.2756% 0 Missing and 6 partials ⚠️
...src/main/groovy/grails/util/GrailsNameUtils.groovy 96.8750% 0 Missing and 5 partials ⚠️
...in/groovy/org/grails/io/support/UrlResource.groovy 91.1765% 2 Missing and 1 partial ⚠️
...org/grails/build/parsing/DefaultCommandLine.groovy 97.5904% 0 Missing and 2 partials ⚠️
...ls/io/support/AbstractFileResolvingResource.groovy 95.2381% 2 Missing ⚠️
...le/model/src/main/groovy/grails/util/Holder.groovy 94.7368% 0 Missing and 1 partial ⚠️
...vy/org/grails/io/support/FileSystemResource.groovy 96.4286% 0 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@                Coverage Diff                 @@
##               10.0.x     #16744        +/-   ##
==================================================
+ Coverage     63.7632%   64.7450%   +0.9817%     
- Complexity      28262      30548      +2286     
==================================================
  Files            2260       2370       +110     
  Lines          112201     116565      +4364     
  Branches        20361      21308       +947     
==================================================
+ Hits            71543      75470      +3927     
+ Misses          31507      31483        -24     
- Partials         9151       9612       +461     
Files with missing lines Coverage Δ
...pache/grails/gradle/common/XmlParserFeature.groovy 100.0000% <100.0000%> (ø)
...src/main/groovy/grails/util/CollectionUtils.groovy 100.0000% <100.0000%> (ø)
...el/src/main/groovy/grails/util/SupplierUtil.groovy 90.4762% <100.0000%> (ø)
...main/groovy/org/grails/build/parsing/Option.groovy 100.0000% <100.0000%> (ø)
...ovy/org/grails/build/parsing/ParseException.groovy 100.0000% <100.0000%> (ø)
...org/grails/io/support/DefaultResourceLoader.groovy 100.0000% <100.0000%> (ø)
...le/model/src/main/groovy/grails/util/Holder.groovy 92.0000% <94.7368%> (ø)
...vy/org/grails/io/support/FileSystemResource.groovy 96.8750% <96.4286%> (ø)
...org/grails/build/parsing/DefaultCommandLine.groovy 97.5904% <97.5904%> (ø)
...ls/io/support/AbstractFileResolvingResource.groovy 90.7407% <95.2381%> (ø)
... and 6 more

... and 282 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.

…asses

A javap -protected diff of the Java and Groovy jars found three changes
the conversion should not make, and one change of behaviour:

- GrailsResourceUtils: DOMAIN_PATH_PATTERN, RESOURCE_PATH_PATTERN,
  SPRING_SCRIPTS_PATH_PATTERN and COMPILER_ROOT_PATTERNS were public
  static fields in Java; without a modifier Groovy made them properties,
  so the fields a compiled Java caller reads were gone. They are
  declared public again.
- CommandLineParser.ENV_ARGS and DEFAULT_ENVS, and
  GrailsNameUtils.convertValidPropertyMethodSuffix, were package-private
  and had become public; they are @PackageScope again.
- SpringIOUtils checked its arguments with assert, which Java skips
  without -ea and Groovy always runs, turning a missing argument into an
  AssertionError. The checks are Objects.requireNonNull with the same
  messages, the NullPointerException a Java caller got. The spec now
  expects that exception and its message for all fifteen checks.

JavaCallerPin, compiled with the model tests, pins the public fields, a
constant of each kind, the constructors and the checked exceptions; with
DOMAIN_PATH_PATTERN made a property again it fails to compile.

Claude-Session: https://claude.ai/code/session_01MDHn7fC3hsGJ27vFHD2o1p
@testlens-app

testlens-app Bot commented Oct 24, 2026

Copy link
Copy Markdown

🔎 No tests executed 🔎

🏷️ Commit: 4661510
▶️ 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

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

2 participants