[
https://issues.apache.org/jira/browse/WW-5768?focusedWorklogId=1047079&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-1047079
]
ASF GitHub Bot logged work on WW-5768:
--------------------------------------
Author: ASF GitHub Bot
Created on: 12/Oct/26 18:23
Start Date: 12/Oct/26 18:23
Worklog Time Spent: 10m
Work Description: lukaszlenart opened a new pull request, #2008:
URL: https://github.com/apache/struts/pull/2008
Fixes [WW-5768](https://issues.apache.org/jira/browse/WW-5768)
## Summary
This is the first adopter of package-scoped constants (WW-3476). A package
can now override the default UI theme and template directory, and child
packages inherit the override through `extends`:
```xml
<package name="admin" extends="struts-default" namespace="/admin">
<scoped-constant name="struts.ui.theme" value="css_xhtml"/>
<scoped-constant name="struts.ui.templateDir" value="admin-template"/>
</package>
```
- `StrutsUiScopableConstants` registers the two names in `struts-beans.xml`,
and in `StrutsDefaultConfigurationProvider` for the test harness.
- `UIBean.getTheme()` / `getTemplateDir()` change only their last fallback
step. It now calls `ScopedConstantProvider.getValue(...)`, which returns the
package override or the global constant.
- The tag attribute, the enclosing form (theme only) and the
request/session/application attribute keep their precedence.
- With no action invocation, for example a JSP rendered directly, the
global constant is used, as before.
## Compatibility
- `setDefaultUITheme` / `setDefaultTemplateDir` and the `defaultUITheme` /
`defaultTemplateDir` fields are no longer injected or read. They are marked
`@Deprecated(since = "7.5.0", forRemoval = true)`, and their removal is tracked
in a separate ticket for 8.0.0.
- `UIBean` now requires an injected `ScopedConstantProvider`, the same way
it already requires a `CspNonceReader`. Components created by the container
(JSP, FreeMarker and Velocity tags) are unaffected. Code that builds components
by hand without `container.inject(...)` must set one: the javatemplates tests
now call `setScopedConstantProvider(name -> null)` next to their existing
`setCspNonceReader(...)`.
- When no override exists, each `getTheme()` / `getTemplateDir()` call now
performs a container lookup of the global constant instead of reading a field.
- A `<scoped-constant>` with an empty value yields an empty theme. This
matches the provider's existing contract (`testEmptyOverrideIsReturnedAsIs`).
## Tests
- New `UIBeanScopedConstantsTest` loads `struts-default.xml` (and therefore
`struts-beans.xml`). It covers:
- the override is used when the tag sets no attribute;
- a child package inherits the override;
- the global value is used with no override and with no invocation;
- the tag attribute, the form's theme and a request attribute each still
win over the override.
- A mutation that put the package value first in `getTheme()` made the form
and request-attribute tests fail, so those tests do exercise the ordering.
- `ScopedConstantsValidationTest`:
- New: a `<scoped-constant name="struts.ui.theme">`, which was rejected
before this change, now loads.
- The "Scopable constants" message now lists the UI names.
- The "no constants are scopable" case now loads only the bootstrap beans,
because the default harness always registers the UI names.
- `UIBeanTest` injects the provider or stubs it, instead of calling the
deprecated setter.
Results:
- `core`: 3456 tests, 0 failures.
- All plugin modules pass, including javatemplates (80), json (177) and
tiles (565).
- The showcase integration tests were not run.
## Follow-up
- struts-site: list these two constants as scopable in
`core-developers/package-configuration.md` (apache/struts-site#351), and
mention the override on the themes and templates page.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Issue Time Tracking
-------------------
Worklog Id: (was: 1047079)
Remaining Estimate: 0h
Time Spent: 10m
> Make struts.ui.theme and struts.ui.templateDir scopable per package
> -------------------------------------------------------------------
>
> Key: WW-5768
> URL: https://issues.apache.org/jira/browse/WW-5768
> Project: Struts 2
> Issue Type: Improvement
> Components: Core Tags
> Reporter: Lukasz Lenart
> Priority: Major
> Fix For: 7.5.0
>
> Time Spent: 10m
> Remaining Estimate: 0h
>
> The first adopter of package-scoped constants
> ([WW-3476|https://issues.apache.org/jira/browse/WW-3476]). That change
> shipped the mechanism only, and no constant is scopable yet, so any
> {{<scoped-constant>}} currently fails at startup.
> h2. Goal
> Allow a package to override the default UI theme and template directory:
> {code:xml}<package name="admin" extends="struts-default" namespace="/admin">
> <scoped-constant name="struts.ui.theme" value="css_xhtml"/>
> <scoped-constant name="struts.ui.templateDir" value="admin-template"/>
> ...
> </package>
> {code}
> Child packages inherit the override through {{extends}}. Today the same
> effect needs a {{theme}} attribute on every tag, or an interceptor that puts
> {{theme}} into the request scope.
> h2. Why these two constants
> {{UIBean.getTheme()}} and {{UIBean.getTemplateDir()}} resolve their values
> when a tag renders, inside the result, so the action invocation and its
> package are known. The injected global value is only the last step of an
> existing chain:
> # the tag attribute
> # the enclosing form (theme only)
> # the request / session / application {{theme}} / {{templateDir}} attribute
> # the injected {{defaultUITheme}} / {{defaultTemplateDir}}
> Only step 4 changes. Everything users rely on today keeps its precedence.
> h2. Proposed change
> * Register a {{ScopableConstants}} bean in {{struts-beans.xml}} (for example
> {{StrutsUiScopableConstants}}) that returns {{struts.ui.theme}} and
> {{struts.ui.templateDir}}.
> * Inject {{ScopedConstantProvider}} into {{UIBean}}, and in step 4 use
> {{scopedConstantProvider.getValue(...)}} instead of the injected field. The
> provider already falls back to the global constant when there is no
> invocation (a JSP rendered without an action) or no override.
> * Register the bean in {{StrutsDefaultConfigurationProvider}} too, for the
> test harness.
> h2. Tests
> * A package override is used when the tag has no {{theme}} / {{templateDir}}.
> * The tag attribute, the enclosing form's theme, and a request-scope
> {{theme}} attribute still win over the override.
> * A child package inherits the parent's override.
> * With no invocation, or no override, the global constant is used.
> * The previously rejected {{<scoped-constant name="struts.ui.theme">}} now
> loads, and an unrelated name is still rejected at startup.
> h2. Docs
> Update the struts-site page for scoped constants
> ({{package-configuration.md}}, see struts-site PR #351) to list these two as
> the scopable constants, and mention the override in the themes and templates
> page.
> h2. Out of scope
> * {{struts.ui.theme.expansion.token}} and {{struts.ui.staticContentPath}}
> * {{struts.convention.result.path}}: it is read at startup by
> {{DefaultResultMapBuilder}}, when there is no invocation, so it needs a
> lookup by package name. That is a separate ticket.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)