Skip to content

WW-3476 Add package-scoped constants - #2005

Merged
lukaszlenart merged 16 commits into
mainfrom
WW-3476-scoped-constants
Oct 11, 2026
Merged

lukaszlenart merged 16 commits into
mainfrom
WW-3476-scoped-constants

Conversation

@lukaszlenart

Copy link
Copy Markdown
Member

Fixes WW-3476

Summary

Adds package-scoped constants: a <package> can override selected constants, and child packages inherit the override through extends.

<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 7.5//EN"
    "https://struts.apache.org/dtds/struts-7.5.dtd">
<package name="admin" extends="struts-default" namespace="/admin">
    <scoped-constant name="some.scopable.constant" value="x"/>
</package>
  • struts-7.5.dtd: a copy of 6.5 plus a repeatable <scoped-constant name value/> as the first child of <package>. Published DTDs are unchanged; this follows the WW-5409 / struts-6.5.dtd precedent.
  • PackageConfig: stores the package's own overrides (getScopedConstants()) and, at build(), a merged view (getAllScopedConstants()). Parents merge first and the package's own entries win, in the same order as getAllResultTypeConfigs().
  • ScopableConstants: components opt a constant in by registering a named bean. The scopable set is the union of all registered beans.
  • Startup validation: DefaultConfiguration rejects a <scoped-constant> whose name no bean registered, including in abstract packages, so a typo or an override nothing reads fails loudly.
  • ScopedConstantProvider.getValue(name) (default StrutsScopedConstantProvider): resolves the value against the current invocation's package and falls back to the global constant. The value already injected into singletons is never changed. It is wired like ParameterAuthorizer: struts-beans.xml, a StrutsBeanSelectionProvider alias, and struts.scopedConstantProvider.

Design notes

  • Opt-in, no adopters yet. Constants are injected into singletons once at startup, so transparently overriding every constant per package would need a container per package. That is out of reach for 7.x. Instead, each component that wants a scoped value reads it through the provider. No constant is registered as scopable in this PR; each adopter (UI theme, i18n, Convention result path, …) is a follow-up.
  • Some constants can never be scoped: anything consumed before the package is known, such as the ActionMapper or multipart limits. The per-URL-space mapper need from the ticket is already covered by PrefixBasedActionMapper (struts.mapper.prefixMapping).
  • Security switches should not be registered as scopable without a deliberate decision (struts.parameters.requireAnnotations, DMI, CSP, devMode). Otherwise a single package could relax an application-wide setting.
  • Values are static strings. No ${...} evaluation.

Design spec and implementation plan: docs/superpowers/specs/2026-10-10-WW-3476-scoped-constants-design.md, docs/superpowers/plans/2026-10-10-WW-3476-scoped-constants.md.

Follow-ups

  • Publish dtds/struts-7.5.dtd on struts-site before the release (rename the DTD and its public id together if the release ships under a different version).

Test plan

  • PackageConfigTest: child overrides parent, two-level inheritance, which of several parents wins, builder copy, unmodifiable maps, equality
  • XmlConfigurationProviderPackagesTest: parse and inherit, duplicate name fails, element rejected under the 6.5 DTD
  • ScopedConstantsValidationTest: registered name loads, unregistered and abstract-package overrides fail, no registry, union of several beans
  • StrutsScopedConstantProviderTest: package value wins, inherited value, empty override, global fallback (no context, invocation, proxy, config or package), unset constant gives null, unregistered name throws, global value untouched
  • ScopedConstantProviderWiringTest: the Dispatcher path resolves StrutsScopedConstantProvider
  • ./mvnw test -DskipAssembly -pl core,plugins/convention: core 3439/3439, convention 66/66

🤖 Generated with Claude Code

lukaszlenart and others added 7 commits October 10, 2026 16:30
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Wire the provider like other pluggable core services (struts-beans.xml,
StrutsBeanSelectionProvider alias, struts.scopedConstantProvider).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…errides

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…cher path

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@lukaszlenart
lukaszlenart marked this pull request as ready for review October 10, 2026 16:07
lukaszlenart and others added 5 commits October 10, 2026 18:08
…ures

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tance

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…om the container once

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comment thread core/src/main/java/org/apache/struts2/StrutsConstants.java
lukaszlenart and others added 2 commits October 10, 2026 18:24
…Names

Matches the Container contract ContainerImpl follows; callers iterate the
result without a null check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tion extension point

Lists it in the StrutsBeanSelectionProvider extension-point table, adds
struts.scopedConstantProvider to default.properties, and pins that the
constant selects a custom bean.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

It changes core configuration parsing, inheritance, startup validation, and dependency-injection APIs, warranting final human review.

0 open findings

What changed in this PR

Introduces opt-in package-scoped Struts constants with inheritance, startup validation, and runtime resolution.

Changes:

  • Adds the 7.5 DTD and package configuration storage/parsing.
  • Adds scopable-constant registration, validation, and provider wiring.
  • Adds comprehensive configuration, inheritance, fallback, and wiring tests.
File Description
docs/​superpowers/​specs/​2026-10-10-WW-3476-scoped-constants-design.md Documents the design.
docs/​superpowers/​plans/​2026-10-10-WW-3476-scoped-constants.md Records the implementation plan.
core/​src/​test/​resources/​org/​apache/​struts2/​config/​struts-scoped-constants-unregistered.xml Tests unregistered constants.
core/​src/​test/​resources/​org/​apache/​struts2/​config/​struts-scoped-constants-two-beans.xml Tests multiple registries.
core/​src/​test/​resources/​org/​apache/​struts2/​config/​struts-scoped-constants-registered.xml Tests registered constants.
core/​src/​test/​resources/​org/​apache/​struts2/​config/​struts-scoped-constants-provider.xml Provides lookup scenarios.
core/​src/​test/​resources/​org/​apache/​struts2/​config/​struts-scoped-constants-no-registry.xml Tests an empty registry.
core/​src/​test/​resources/​org/​apache/​struts2/​config/​struts-scoped-constants-custom-provider.xml Configures a custom provider.
core/​src/​test/​resources/​org/​apache/​struts2/​config/​struts-scoped-constants-abstract-unregistered.xml Tests abstract-package validation.
core/​src/​test/​resources/​org/​apache/​struts2/​config/​providers/​struts-scoped-constants-old-dtd.xml Tests old-DTD rejection.
core/​src/​test/​resources/​org/​apache/​struts2/​config/​providers/​struts-scoped-constants-inheritance.xml Tests package inheritance.
core/​src/​test/​resources/​org/​apache/​struts2/​config/​providers/​struts-scoped-constants-duplicate.xml Tests duplicate rejection.
core/​src/​test/​java/​org/​apache/​struts2/​config/​StrutsScopedConstantProviderTest.java Tests runtime resolution and fallback.
core/​src/​test/​java/​org/​apache/​struts2/​config/​SecondScopableConstants.java Supplies a second test registry.
core/​src/​test/​java/​org/​apache/​struts2/​config/​ScopedConstantsValidationTest.java Tests startup validation.
core/​src/​test/​java/​org/​apache/​struts2/​config/​ScopedConstantProviderWiringTest.java Tests provider selection.
core/​src/​test/​java/​org/​apache/​struts2/​config/​ScopableConstantsTest.java Tests registry collection.
core/​src/​test/​java/​org/​apache/​struts2/​config/​SampleScopableConstants.java Supplies test constant names.
core/​src/​test/​java/​org/​apache/​struts2/​config/​providers/​XmlConfigurationProviderPackagesTest.java Tests XML parsing behavior.
core/​src/​test/​java/​org/​apache/​struts2/​config/​entities/​PackageConfigTest.java Tests storage and inheritance.
core/​src/​test/​java/​org/​apache/​struts2/​config/​CustomScopedConstantProvider.java Supplies a custom test provider.
core/​src/​main/​resources/​struts-beans.xml Registers the default provider bean.
core/​src/​main/​resources/​struts-7.5.dtd Defines package-scoped constants.
core/​src/​main/​resources/​org/​apache/​struts2/​default.properties Selects the default provider.
core/​src/​main/​java/​org/​apache/​struts2/​StrutsConstants.java Adds the provider-selection key.
core/​src/​main/​java/​org/​apache/​struts2/​mock/​MockContainer.java Aligns mock instance-name behavior.
core/​src/​main/​java/​org/​apache/​struts2/​config/​StrutsXmlConfigurationProvider.java Registers the new DTD.
core/​src/​main/​java/​org/​apache/​struts2/​config/​StrutsScopedConstantProvider.java Implements scoped lookup.
core/​src/​main/​java/​org/​apache/​struts2/​config/​StrutsBeanSelectionProvider.java Adds provider alias selection.
core/​src/​main/​java/​org/​apache/​struts2/​config/​ScopedConstantProvider.java Defines the lookup API.
core/​src/​main/​java/​org/​apache/​struts2/​config/​ScopableConstants.java Defines the opt-in registry.
core/​src/​main/​java/​org/​apache/​struts2/​config/​providers/​XmlDocConfigurationProvider.java Parses scoped constants.
core/​src/​main/​java/​org/​apache/​struts2/​config/​providers/​StrutsDefaultConfigurationProvider.java Registers the test-harness provider.
core/​src/​main/​java/​org/​apache/​struts2/​config/​impl/​DefaultConfiguration.java Validates declarations at startup.
core/​src/​main/​java/​org/​apache/​struts2/​config/​entities/​PackageConfig.java Stores and merges scoped values.

🧠 Review effort: Balanced


💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

lukaszlenart and others added 2 commits October 11, 2026 09:51
….providers

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
c939805 committed only the renames; this adds the package declarations,
imports and the struts-beans.xml class name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@lukaszlenart
lukaszlenart merged commit fd60b20 into main Oct 11, 2026
18 checks passed
@lukaszlenart
lukaszlenart deleted the WW-3476-scoped-constants branch October 11, 2026 08:14
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