Skip to content

Add groovy.io.fileLegacyTruthy system property to opt out of new File/Path truthy semantics#2513

Closed
pditommaso wants to merge 2 commits into
apache:masterfrom
pditommaso:add-file-legacy-truthy-property
Closed

Add groovy.io.fileLegacyTruthy system property to opt out of new File/Path truthy semantics#2513
pditommaso wants to merge 2 commits into
apache:masterfrom
pditommaso:add-file-legacy-truthy-property

Conversation

@pditommaso
Copy link
Copy Markdown
Contributor

Summary

Adds an opt-out system property that restores the pre-Groovy-5 truthy semantics for java.io.File and java.nio.file.Path: when -Dgroovy.io.fileLegacyTruthy=true is set, any non-null reference is truthy, regardless of whether the underlying file exists.

The new default behaviour introduced in 5.0 (delegating to File.exists() / Files.exists()) is preserved when the property is absent or false.

Why

The new truthy semantics for File/Path introduced in Groovy 5 are a useful upgrade for greenfield code, but they silently change the behaviour of any existing code that uses if (path) { … } or path ? a : b to mean "the reference is set". The release notes call this out and recommend rewriting affected sites to use explicit != null.

That recommendation is reasonable for code authors who control the codebase, but it does not generalise. In platforms that execute user-supplied Groovy code — Nextflow being one example, but the same applies to Gradle build scripts, Jenkins pipelines, and many other Groovy-based DSLs — the upgrade does not just affect the platform itself. Every existing user pipeline written against earlier Groovy versions can be silently affected, and there is no realistic path to audit and rewrite all of them. The end-user authoring those pipelines may have no idea Groovy was upgraded under them, and a previously-working if(file) may now silently skip a branch when the referenced file happens not to exist yet at evaluation time.

A toggle flag here lets such platforms upgrade to Groovy 5 without forcing a coordinated rewrite of an unbounded set of downstream user code. Greenfield Groovy 5 users continue to get the new default; platform integrators have an explicit, well-named knob to preserve compatibility for their users.

Implementation

  • New system property: groovy.io.fileLegacyTruthy (single shared flag covering both File and Path, named per Groovy's existing convention — see groovy.compiler.strictNames, groovy.json.internKeys, etc.).
  • Two changes:
    • ResourceGroovyMethods.asBoolean(File) — opt-out branch returns file != null.
    • NioExtensions.asBoolean(Path) — opt-out branch returns path != null.
  • Read once at class load via SystemUtil.getBooleanSafe(...) to match the pattern used elsewhere (StaticTypeCheckingVisitor.DEBUG_GENERATED_CODE, CompilerConfiguration.parameters, …).
  • Javadoc updated on both methods.

The default path is unchanged (no behaviour change, no perf impact beyond a single boolean read at JVM start).

Test plan

  • Verify default behaviour (property absent) still calls File.exists() / Files.exists() — covered by the existing ResourceGroovyMethodsTest.test_asBoolean.
  • Add a test exercising the opt-out path. Note: because the constant is initialised at class load, this test needs to set the system property before the class is loaded (forked JVM, or junit-pioneer @SetSystemProperty). Happy to add the test in this PR if a particular fixture style is preferred — let me know.

Notes

  • Single property covers both File and Path because the breaking change is conceptually the same; users are likely to want to flip both together.
  • No CHANGELOG / release-note entry yet — happy to add one in the form preferred by the project.

Restore the pre-Groovy 5 truthy semantics for `java.io.File` and
`java.nio.file.Path` when the system property
`-Dgroovy.io.fileLegacyTruthy=true` is set: any non-null reference is
truthy, regardless of whether the underlying file exists.

The default behavior introduced in 5.0 (delegating to
`File.exists()` / `Files.exists()`) is preserved when the property is
absent or false.
@paulk-asert
Copy link
Copy Markdown
Contributor

Are you up for creating a JIRA ticket for this? Or let me know and I can create one.
We tend to not have capital letters in system properties and often avoid things like legacy but state the opposite and let it be set to false to turn off, e.g. groovy.truth.file.exists.enabled (default to true).

Address review feedback: avoid capital letters in system properties and
state the positive behavior, defaulting to enabled. Setting the property
to `false` restores the pre-Groovy-5 truthy semantics for `File`/`Path`
(any non-null reference is truthy).

The flag is defined once in `ResourceGroovyMethods.FILE_EXISTS_ENABLED`
and reused from `NioExtensions` so both extensions stay in sync.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@pditommaso
Copy link
Copy Markdown
Contributor Author

Thanks for the quick reply. I'm totally open to naming and code improvements — I've pushed a commit using the suggested name groovy.truth.file.exists.enabled (default: true) and reused the same constant to avoid duplicating the definition.

I'd appreciate it if you could open the Jira ticket.

One more question: do you think this change could reasonably be back-ported to the Groovy 5 branch?

@testlens-app
Copy link
Copy Markdown

testlens-app Bot commented May 5, 2026

✅ All tests passed ✅

🏷️ Commit: 4a5ad4b
▶️ Tests: 97171 executed
⚪️ Checks: 20/20 completed


Learn more about TestLens at testlens.app.

@paulk-asert
Copy link
Copy Markdown
Contributor

I created this:
https://issues.apache.org/jira/browse/GROOVY-11996

@paulk-asert
Copy link
Copy Markdown
Contributor

Proposed PR merged. Thanks! Will be on the next 6 release and 5.0.7.

@paulk-asert paulk-asert closed this May 6, 2026
@pditommaso
Copy link
Copy Markdown
Contributor Author

Thanks a lot, this is great 🙏

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