Make profile activation conditions locale-independent - #12735
Make profile activation conditions locale-independent#12735SEPURI-SAI-KRISHNA wants to merge 1 commit into
Conversation
upper() and lower() called String.toUpperCase()/toLowerCase() without a
Locale, and ConditionParser.toString() formatted whole doubles with
String.format() without a Locale. All three therefore depended on the
default locale of the machine running the build, so the same POM could
activate different profiles on different machines.
Turkish maps i to the dotted capital İ, so upper('windows') returns
WİNDOWS and a condition such as upper(${os.name}) == 'WINDOWS' silently
fails to activate. Under a locale whose default numbering system is not
latin, such as hi-IN-u-nu-deva, toString(42.0) returns ४२ rather than
42.
Use Locale.ROOT in all three places, matching ExecutableFinder in the
same package and the other explicit-Locale call sites in the codebase.
The existing tests missed this because none of the strings they convert
contain an i or I. Add tests pinning the behaviour under tr and
hi-IN-u-nu-deva; both fail without the production change.
gnodet
left a comment
There was a problem hiding this comment.
Well-scoped, correct fix for a real locale-sensitivity bug in profile activation condition evaluation. All three locale-sensitive call sites are properly fixed (upper() and lower() in ConditionFunctions.java, toString() in ConditionParser.java).
The tests are thorough and follow the established save/restore pattern from VersionTest.testCaseInsensitiveOrderingOfQualifiersIsLocaleIndependent. Good choice of test inputs — strings containing i/I (affected by Turkish locale case mapping) and a locale with Devanagari numbering for the number formatting test.
Minor nit: new Locale("tr") is deprecated since Java 19 in favor of Locale.of("tr"), but the existing codebase uses the same deprecated constructor in VersionTest.java, so this is consistent.
Excellent PR description with reproduction steps and explanation of why existing tests missed the bug.
This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.
Claude Code on behalf of gnodet
What
Uses
Locale.ROOTin the three places where profile activation condition evaluation wasimplicitly relying on the JVM default locale:
ConditionFunctions.upper(..)—toUpperCase()→toUpperCase(Locale.ROOT)ConditionFunctions.lower(..)—toLowerCase()→toLowerCase(Locale.ROOT)ConditionParser.toString(..)—String.format("%.0f", ..)→String.format(Locale.ROOT, "%.0f", ..)Why
Profile activation should not depend on the locale of the machine running the build, but today
it does. Turkish and Azeri map
ito the dottedİandIto the dotlessı, so this profile:silently fails to activate on a JVM started with
-Duser.language=tr, becauseupper('windows')returns
WİNDOWS. Reproduction:ConditionParser.toString(Object)has the same class of problem: it formats whole doubles withString.format("%.0f", ..)and noLocale, so under a locale whose default numbering system isnot latin (e.g.
hi-IN-u-nu-deva) it renders42as४२.This brings the three call sites in line with the rest of the codebase, which already passes an
explicit
Localein ~41 places — includingExecutableFinder, in this same package.Why the existing tests missed it
Every string the current tests convert (
hello,WORLD,success,HELLO WORLD) happens tocontain no
iorI, soConditionParserTestpasses unchanged under-Duser.language=tr.Tests
Two tests added to
ConditionParserTest, both of which fail without the production change:testCaseConversionFunctionsAreLocaleIndependent— exercisesupper/lowerunderenandtrtestNumberFormattingIsLocaleIndependent— exercises number rendering underhi-IN-u-nu-devaThey follow the existing save/restore pattern from
VersionTest.testCaseInsensitiveOrderingOfQualifiersIsLocaleIndependentin the same module.Reverting only the production change and re-running gives:
With the change, the full
maven-implmodule suite passes: 552 tests, 0 failures, checkstyle /spotless / rat clean.
If this is wanted on
maven-4.0.xas well, happy for it to be backported.PR checklist
The template ships with this checklist. Tick these:
mvn verifyto make sure basic checks pass.Leave UNTICKED unless you actually run it (see note below):
The ICLA line can stay unticked — the production change is ~20 lines, under the template's
"~20 lines of code" threshold.