Fix initializr localization bundle path (NPE in MyAppName.init)#4852
Merged
shai-almog merged 5 commits intomasterfrom May 2, 2026
Merged
Fix initializr localization bundle path (NPE in MyAppName.init)#4852shai-almog merged 5 commits intomasterfrom
shai-almog merged 5 commits intomasterfrom
Conversation
The initializr's "include localization bundles" option generated bundles
under common/src/main/resources/messages*.properties, but the CN1 maven
plugin's CSS compiler scans common/src/main/l10n (or i18n) for bundles to
bake into theme.res. The result: Resources.getGlobalResources().getL10N(
"messages", lang) hit a missing resource id at simulator startup and
threw NPE in MyAppName.init -- the project couldn't run.
- GeneratorModel.addLocalizationEntries: write to src/main/l10n so the
bundles actually end up inside theme.res.
- Bootstrap (Java + Kotlin) injected into the starter class is now
null-safe and falls back to the default locale when the device
language has no specific bundle.
- Resources.getL10N / listL10NLocales / l10NLocaleSet now return null
instead of NPE-ing when the bundle id is absent. Defensive change at
the framework level so any project shipping mismatched bundles
degrades gracefully.
- New tests/core/.../ResourcesL10NTest covers the framework null-safety.
- GeneratorModelMatrixTest now asserts bundles land under l10n and are
NOT under src/main/resources (catches the regression at unit-test
time).
- GeneratorModelIntegrationBuildTest now opens common/target/classes/
theme.res after mvn compile and verifies "messages" L10N data is
present for both the default ("") and Hebrew ("he") locales -- the
end-to-end signal the previous tests missed.
While here, harden the simulator's CSS compiler invocation against
stale ~/.codenameone/designer_1.jar:
- New MavenUtils.findDesignerJarInM2 derives the running CN1 version
from the codenameone-core jar's m2 path and resolves the matching
codenameone-designer-<version>-jar-with-dependencies.jar. Any plugin
invocation has already pulled this into m2 as a plugin dependency.
- CSSWatcher and ComponentTreeInspector now prefer codename1.designer.jar
-> m2 designer -> ~/.codenameone fallback (with a clear warning when
the legacy fallback is hit). The build-time CSS goal already used
getDesignerJar() so this only affects the simulator runtime / live
CSS reload paths.
- CompileCSSMojo now invokes the forked CSS compiler with INFO log
level instead of DEBUG so subprocess stack traces are visible without
re-running with -X. This won't fix issue #4850 but makes the next
similar report actionable.
- The four initializr pom templates replace skipexisting="true" with
usetimestamp="true" on the UpdateCodenameOne.jar download so future
installs refresh the updater jar instead of pinning forever to the
first copy.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Collaborator
Author
|
Compared 7 screenshots: 7 matched. |
The previous patch raised the CSS subprocess log level by passing it explicitly at the call site (createJava(LEVEL_INFO)), which bypasses CompileCSSMojoTest's TestCompileCSSMojo.createJava() override -- the test substitutes a RecordingJava there to capture the command line without forking. The override was no longer hit, so the test fell through to a real fork against a stub designer.jar and four tests errored out with "Invalid or corrupt jarfile". Move the INFO log level into a createJava() override on CompileCSSMojo itself. The call site stays at createJava(), so the test override continues to win, and production still gets INFO so subprocess stack traces remain visible without -X. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contributor
Cloudflare Preview
|
Contributor
✅ Continuous Quality ReportTest & Coverage
Static Analysis
Generated automatically by the PR CI workflow. |
Collaborator
Author
|
Compared 86 screenshots: 86 matched. Native Android coverage
✅ Native Android screenshot tests passed. Native Android coverage
Benchmark ResultsDetailed Performance Metrics
|
Collaborator
Author
The user shared the missing stack trace from issue #4850: at java.base/java.lang.String.substring(String.java:2899) at com.codename1.ui.plaf.UIManager.parseTextFieldInputMode(UIManager.java:2434) at com.codename1.ui.plaf.UIManager.setBundle(UIManager.java:2419) at com.codename1.impl.javase.JavaSEPort.enableAutoLocalizationBundle(...) at com.codename1.impl.javase.JavaSEPort.init(JavaSEPort.java:5598) at com.codename1.impl.CodenameOneImplementation.initImpl(...) at com.codename1.ui.Display.init(Display.java:351) at com.codename1.designer.css.CN1CSSCLI.main(CN1CSSCLI.java:713) This is not a path-related bug -- every initializr-generated project hits it at css-goal time. Three pieces interact: 1. JavaSEPort.findLocalizationDirectory auto-creates src/main/l10n if it is missing, and enableAutoLocalizationBundle installs an AutoLocalizationBundle for it. 2. AutoLocalizationBundle.get echoes any missing key back as its own value -- the simulator's "wormhole" so devs can spot untranslated strings. 3. UIManager.setBundle queries "@im" on every bundle install. With the echo behavior, "@im" -> "@im", which is then tokenized to ["@im"], "@im-@im" is queried (which echoes "@im-@im"), and parseTextFieldInputMode crashes on substring(0, indexOf('=')) because that token has no '=' (range [0, -1) of length 7). The CSS compiler subprocess inherits all of this because CN1CSSCLI.main calls Display.init -> JavaSEPort.init -> enableAutoLocalizationBundle. Fixes: - AutoLocalizationBundle.get returns null for keys starting with '@'. Meta-keys (@rtl, @im, @im-<name>) are configuration entries that callers distinguish from "missing" by checking for null. Echoing the key back is semantically wrong AND broke setBundle. Real meta-key values that exist in the underlying file (e.g. @rtl=true in a Hebrew bundle) are still returned -- only fabrication is suppressed. - UIManager.parseTextFieldInputMode skips tokens without '=' and skips entries whose key isn't a valid integer. Defensive belt-and-suspenders so any bundle with malformed input-mode entries degrades gracefully instead of failing the whole bundle install. - New UIManagerSetBundleTest exercises setBundle against an echo-bundle (matches pre-fix AutoLocalizationBundle behavior) and against directly malformed @im/@im-x entries. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… fix Per review: silently skipping malformed `@im` tokens hides legitimate bugs in user-supplied bundles. Real malformed input should fail loudly, not be swallowed. The actual root cause -- AutoLocalizationBundle fabricating values for @-prefixed meta-keys -- stays fixed. That's the surgical change: the auto-localize wormhole was returning fake values for keys that callers explicitly use null/non-null to gate features (@im, @rtl, @im-<name>), which is semantically wrong and broke setBundle. Moves the regression coverage from the no-op stub in core to the existing AutoLocalizationBundleTest in the JavaSE port (where the bundle class actually lives), asserting: - @-prefixed meta-keys are NOT auto-fabricated - @-prefixed meta-keys that exist in the underlying file ARE returned Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…wormhole Workaround for the AutoLocalizationBundle @im fabrication crash in shipped Codename One <= 7.0.236. The proper fix lives in JavaSEPort (don't fabricate values for `@`-prefixed meta-keys) and is on this branch, but it requires a new framework release. Until then, every initializr-generated project crashes at css-goal time inside the CSS compiler subprocess (CN1CSSCLI -> Display.init -> JavaSEPort.init -> enableAutoLocalizationBundle -> UIManager.setBundle -> parseTextFieldInputMode on substring(0, -1) for "@im-@im"). Ship `common/src/main/l10n/Bundle.properties` with a single `@im=` entry on every generated project. Two reasons it works: 1. JavaSEPort.findDefaultLocalizationBundleFile prefers Bundle.properties over any other file in src/main/l10n, so the AutoLocalizationBundle loads our stub as its base. 2. With `@im=""` already in the bundle's underlying Hashtable, AutoLocalizationBundle.get("@im") returns "" instead of fabricating "@im". setBundle sees length 0 and skips the input-mode block, so parseTextFieldInputMode is never called. The stub is unconditional (added to every project, with or without localization bundles enabled) because the bug fires regardless -- enableAutoLocalizationBundle auto-creates src/main/l10n in the CSS compiler subprocess even on projects that didn't request localization. The matrix test asserts the stub is present on every generated project combination so this workaround can't silently regress. Once the AutoLocalizationBundle fix lands in a release and the initializr is bumped past it, this stub can be removed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
NullPointerExceptioninResources.getL10Nwhen running an initializr project generated with the Include localization bundles option. The bundles were written tocommon/src/main/resources/but the CN1 maven plugin's CSS compiler scanscommon/src/main/l10n/(ori18n/), so they were never baked intotheme.res. Moving them tosrc/main/l10n/makes the data actually present in the resource file at runtime.Resources.getL10N/listL10NLocales/l10NLocaleSetto returnnullinstead of NPE-ing when the bundle id is missing -- defensive across all projects, not just initializr ones.l10n/(and explicitly not underresources/), and the integration build test openstheme.resaftermvn compileand verifies themessagesL10N data is present for default + Hebrew locales.codenameone-corejar's path) over~/.codenameone/designer_1.jar, with a clear warning on the legacy fallback. The build-time CSS goal already pinned viagetDesignerJar(); this only changes the simulator runtime path.CompileCSSMojoforks the CSS compiler with INFO log level instead of DEBUG so subprocess stack traces are visible without-X. Addresses the diagnosability gap behind issue Unable to launch simulator because of Java.lang.StringIndexOutOfBoundsException in latest as of reporting (7.0.236) #4850 (does not fix that bug -- the underlying CSS compiler exception is still in there, but next report will arrive with a usable stack trace).barebones,kotlin,grub,tweet) replaceskipexisting=\"true\"withusetimestamp=\"true\"on theUpdateCodenameOne.jardownload so the bootstrapper refreshes when newer instead of pinning forever.Files changed
CodenameOne/src/com/codename1/ui/util/Resources.java-- null-safegetL10N/listL10NLocales/l10NLocaleSet.Ports/JavaSE/src/.../util/MavenUtils.java-- newfindDesignerJarInM2()helper.Ports/JavaSE/src/.../CSSWatcher.java,ComponentTreeInspector.java-- prefer m2 designer over home-dir fallback.maven/codenameone-maven-plugin/.../CompileCSSMojo.java-- INFO log level for CSS subprocess.scripts/initializr/.../GeneratorModel.java-- bundles tosrc/main/l10n/; bootstrap null/locale fallback.scripts/initializr/.../{barebones,kotlin,grub,tweet}-pom.xml--usetimestampon updater download.scripts/initializr/.../GeneratorModelMatrixTest.java-- assertl10n/location, rejectresources/.scripts/initializr/.../GeneratorModelIntegrationBuildTest.java-- post-compile assertion thattheme.resactually contains themessagesbundle.tests/core/src/com/codename1/ui/util/ResourcesL10NTest.java(new) -- framework regression test for null-safe lookups.Test plan
cd scripts/initializr && ./mvnw -pl common test-- matrix + integration tests pass; integration build verifies theme.res content.cd maven && mvn -Plocal-dev-javase -pl javase -am compile-- JavaSE port compiles.cd maven && mvn -Plocal-dev-javase -pl codenameone-maven-plugin -am compile-- plugin compiles.mvn cn1:run-- simulator starts without the previously-reported NPE; on a non-Hebrew/Arabic device the defaultmessages.propertiesfallback is applied.~/.codenameone/designer_1.jarnow logs the m2 path (or the warning if no m2 designer is available).🤖 Generated with Claude Code