Add groovy.io.fileLegacyTruthy system property to opt out of new File/Path truthy semantics#2513
Add groovy.io.fileLegacyTruthy system property to opt out of new File/Path truthy semantics#2513pditommaso wants to merge 2 commits into
groovy.io.fileLegacyTruthy system property to opt out of new File/Path truthy semantics#2513Conversation
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.
|
Are you up for creating a JIRA ticket for this? Or let me know and I can create one. |
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>
|
Thanks for the quick reply. I'm totally open to naming and code improvements — I've pushed a commit using the suggested name 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? |
✅ All tests passed ✅🏷️ Commit: 4a5ad4b Learn more about TestLens at testlens.app. |
|
I created this: |
|
Proposed PR merged. Thanks! Will be on the next 6 release and 5.0.7. |
|
Thanks a lot, this is great 🙏 |
Summary
Adds an opt-out system property that restores the pre-Groovy-5 truthy semantics for
java.io.Fileandjava.nio.file.Path: when-Dgroovy.io.fileLegacyTruthy=trueis set, any non-nullreference 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/Pathintroduced in Groovy 5 are a useful upgrade for greenfield code, but they silently change the behaviour of any existing code that usesif (path) { … }orpath ? a : bto 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
groovy.io.fileLegacyTruthy(single shared flag covering bothFileandPath, named per Groovy's existing convention — seegroovy.compiler.strictNames,groovy.json.internKeys, etc.).ResourceGroovyMethods.asBoolean(File)— opt-out branch returnsfile != null.NioExtensions.asBoolean(Path)— opt-out branch returnspath != null.SystemUtil.getBooleanSafe(...)to match the pattern used elsewhere (StaticTypeCheckingVisitor.DEBUG_GENERATED_CODE,CompilerConfiguration.parameters, …).The default path is unchanged (no behaviour change, no perf impact beyond a single boolean read at JVM start).
Test plan
File.exists()/Files.exists()— covered by the existingResourceGroovyMethodsTest.test_asBoolean.@SetSystemProperty). Happy to add the test in this PR if a particular fixture style is preferred — let me know.Notes
FileandPathbecause the breaking change is conceptually the same; users are likely to want to flip both together.