Skip to content

LDEV-6297 manifest maven: field works end-to-end on 6.2 - #2781

Open
zspitzer wants to merge 3 commits into
lucee:6.2from
zspitzer:LDEV-6297
Open

LDEV-6297 manifest maven: field works end-to-end on 6.2#2781
zspitzer wants to merge 3 commits into
lucee:6.2from
zspitzer:LDEV-6297

Conversation

@zspitzer

@zspitzer zspitzer commented Apr 29, 2026

Copy link
Copy Markdown
Member

Summary

  • 6.2's manifest top-level maven: field accepted only JSON form; the canonical gradle GAV-comma form (per MAVEN-EXTENSION-MIGRATION.md, accepted by 7.x) failed silently with a JSON syntax error logged twice per install.
  • Even when entries registered (JSON form pre-fix, or gradle form post-fix), they never reached the RPC classloader on hot install — only after a server restart.
  • This PR closes both gaps so extensions can ship a single .lex with a gradle GAV-comma manifest and have createObject(\"java\", className) resolve against the registered artefacts on 6.2 + 7.x without a server restart.

JIRA: LDEV-6297

The three commits

b7875ce — accept gradle GAV-comma form in manifest maven: field

  • New RHExtension.toMavenSettings(Log, String) helper. Tries JSON first (preserves existing 6.2 behaviour byte-for-byte), falls back to MavenUtil.toGAVSOs(str, null) for the gradle group:artifact:version[,...] form, converts each GAVSO back into the existing Map<String,String> shape so ConfigAdmin._updateMaven and downstream consumers stay byte-identical.
  • MavenUtil.toGAVSOs already shipped on 6.2 under LDEV-5276 — this just wires it into the manifest read path.
  • Test: test/tickets/LDEV6297.cfc covers 8 format permutations via reflection (single GAV, multi-GAV, JSON struct, JSON array, short-key aliases, whitespace-padded, scope token, and a negative case).
  • Replaces a per-install ERROR log (Syntax Error in JSON) with a single descriptive WARN-level log only when both formats fail.

2463aa0 — refresh cached JavaSettings after extension install

  • After _updateMaven in unSyncUpdateExtension writes maven entries to root.javasettings, calls ConfigWebFactory._loadJavaSettings(null, (ConfigImpl) config, root, logger) to rebuild the cached JavaSettings on ConfigServerImpl. Reuses the existing boot-time helper (visibility widened from private to package-private; same package).
  • Without this, _updateMaven's entries persisted to .CFConfig.json and waited for the next server restart. With it, the same boot-time wiring fires post-install.

6cb3e1c — also invalidate the JVM-level default classloader cache

  • ModernApplicationContext.defaultClassLoader is a private static ClassLoader cached at first use. Both Modern and Classic application contexts route through ModernApplicationContext.getDefaultClassLoader(ConfigWeb) for the request-time classloader. Once cached against pre-install (empty) JavaSettings, refreshing ConfigServer.javaSettings had no effect — the static cache was shadowing it.
  • New ModernApplicationContext.resetDefaultClassLoader() static method nulls the cache; called from the same hook as stage 2 immediately after the JavaSettings refresh.

Why this doesn't mirror 7.x's pattern

7.x took a different architectural path:

  • ConfigImpl.resetJavaSettings() exists and is invoked via ResetFilter reflection (filter.add(\"resetJavaSettings\") in ConfigAdmin.unSyncUpdateExtension).
  • ModernApplicationContext.getRPCClassLoader() is deprecated: throw new RuntimeException(\"the method [getRPCClassLoader()] is no longer supported\");.
  • getDefaultClassLoader(ConfigWeb) exists on 7.x but is uncalled anywhere in the codebase — dead code that survived the deprecation.
  • 7.x's createObject(\"java\", ...) path bypasses the static cache entirely.

Backporting 7.x's path (ResetFilter, resetAll(filter) reflection, getRPCClassLoader deprecation, JavaSettingsImpl.merge, ApplicationContext semantic changes) would be ~300-500 LoC of stable-branch infrastructure work touching application context resolution. We chose the surgical 6.2-specific fix that addresses the actual cache-staleness bug 6.2 has.

The new resetDefaultClassLoader() helper is intentionally branch-specific. 7.x doesn't need an equivalent because its classloader path doesn't read the cache. Future merges from 6.2 → 7.x should drop this helper.

Empirical validation

Probe: 4 createObject(\"java\", className) calls against POI classes (HSSFWorkbook, XSSFWorkbook, SXSSFWorkbook, StreamingReader) using lucee-spreadsheet-extension's feat/maven-refactor .lex with a gradle-form manifest.

Lucee Stage 1 only Stages 1+2 Stages 1+2+3
6.2.7.14-SNAPSHOT, hot install 0/4 0/4 4/4
6.2.7.14-SNAPSHOT, post-restart 4/4 ✅ 4/4 ✅ 4/4 ✅

Confirmed working with lucee-spreadsheet-extension end-to-end (cfspreadsheet operations resolve POI classes correctly post-install).

Limitations on 6.2 vs 7.x (intentionally out of scope)

  1. App-level merge semantics. On 7.x, Application.cfc this.javaSettings merges with server-level. On 6.2 it still replaces. Apps that don't override this.javaSettings see server-level entries fine.
  2. JSON form on 7.x is fatal at install with Missing required field: version. Inverse of the original 6.2 bug. Not fixed here because the canonical form (per migration guide) is gradle GAV-comma — and after this PR lands, that form works on every supported Lucee branch.

Test plan

  • All 8 specs in test/tickets/LDEV6297.cfc pass (parser format coverage)
  • Full mvn test clean for affected paths (LDEV6297 8/8; pre-existing flakes LDEV0407/LDEV4955 are environmental — HTTP test target and VSCode env-var leak respectively)
  • Spreadsheet-extension feat/maven-refactor .lex installs and resolves POI via createObject on hot install with no restart
  • Same .lex resolves POI on post-restart (regression check)

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.

1 participant