This is an automated email from the ASF dual-hosted git repository.
lukaszlenart pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/struts.git
The following commit(s) were added to refs/heads/main by this push:
new 65a8f8668 WW-5768 Make struts.ui.theme and struts.ui.templateDir
scopable per package (#2008)
65a8f8668 is described below
commit 65a8f86689ec887033fbca52f69d0ae18787c082
Author: Lukasz Lenart <[email protected]>
AuthorDate: Mon Oct 12 21:30:00 2026 +0200
WW-5768 Make struts.ui.theme and struts.ui.templateDir scopable per package
(#2008)
* WW-5768 feat(ui): make struts.ui.theme and struts.ui.templateDir scopable
per package
A package can now override the default UI theme and template directory with
<scoped-constant>, and child packages inherit it through extends. Only the
last
fallback in UIBean.getTheme()/getTemplateDir() changes: it asks the
ScopedConstantProvider, which returns the package override or the global
constant. The tag attribute, the enclosing form and the request/session/
application attributes keep their precedence.
setDefaultUITheme/setDefaultTemplateDir and their fields are no longer read
and
are deprecated for removal. Components built without the container now need
a
ScopedConstantProvider, the same way they already need a CspNonceReader; the
javatemplates tests set a stub.
The empty-registry validation test now loads only the bootstrap beans,
because
StrutsDefaultConfigurationProvider registers the UI names.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* WW-5768 docs(ui): add @deprecated Javadoc to the deprecated UIBean fields
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
---
.../components/StrutsUiScopableConstants.java | 37 ++++++
.../java/org/apache/struts2/components/UIBean.java | 26 +++-
.../StrutsDefaultConfigurationProvider.java | 3 +
core/src/main/resources/struts-beans.xml | 2 +
.../components/UIBeanScopedConstantsTest.java | 133 +++++++++++++++++++++
.../org/apache/struts2/components/UIBeanTest.java | 6 +-
.../config/ScopedConstantsValidationTest.java | 32 ++++-
.../apache/struts2/components/struts-scoped-ui.xml | 34 ++++++
.../struts2/config/struts-scoped-constants-ui.xml | 30 +++++
.../struts2/views/java/simple/ActionErrorTest.java | 1 +
.../views/java/simple/ActionMessageTest.java | 1 +
.../struts2/views/java/simple/AnchorTest.java | 1 +
.../struts2/views/java/simple/CheckboxTest.java | 1 +
.../views/java/simple/DateTextFieldTest.java | 1 +
.../struts2/views/java/simple/FieldErrorTest.java | 1 +
.../apache/struts2/views/java/simple/FileTest.java | 1 +
.../apache/struts2/views/java/simple/FormTest.java | 1 +
.../apache/struts2/views/java/simple/HeadTest.java | 1 +
.../struts2/views/java/simple/HiddenTest.java | 1 +
.../struts2/views/java/simple/LabelTest.java | 1 +
.../apache/struts2/views/java/simple/LinkTest.java | 1 +
.../struts2/views/java/simple/PasswordTest.java | 1 +
.../struts2/views/java/simple/ResetTest.java | 1 +
.../struts2/views/java/simple/ScriptTest.java | 1 +
.../struts2/views/java/simple/SelectTest.java | 1 +
.../struts2/views/java/simple/SubmitTest.java | 1 +
.../struts2/views/java/simple/TextAreaTest.java | 1 +
.../struts2/views/java/simple/TextFieldTest.java | 1 +
.../struts2/views/java/simple/TokenTest.java | 1 +
29 files changed, 315 insertions(+), 8 deletions(-)
diff --git
a/core/src/main/java/org/apache/struts2/components/StrutsUiScopableConstants.java
b/core/src/main/java/org/apache/struts2/components/StrutsUiScopableConstants.java
new file mode 100644
index 000000000..1fb0a468e
--- /dev/null
+++
b/core/src/main/java/org/apache/struts2/components/StrutsUiScopableConstants.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.struts2.components;
+
+import org.apache.struts2.StrutsConstants;
+import org.apache.struts2.config.ScopableConstants;
+
+import java.util.Set;
+
+/**
+ * Lets a package override the default UI theme and template directory with
{@code <scoped-constant>}.
+ *
+ * @since 7.5.0
+ */
+public class StrutsUiScopableConstants implements ScopableConstants {
+
+ @Override
+ public Set<String> getNames() {
+ return Set.of(StrutsConstants.STRUTS_UI_THEME,
StrutsConstants.STRUTS_UI_TEMPLATEDIR);
+ }
+}
diff --git a/core/src/main/java/org/apache/struts2/components/UIBean.java
b/core/src/main/java/org/apache/struts2/components/UIBean.java
index 36c51340a..f193230a4 100644
--- a/core/src/main/java/org/apache/struts2/components/UIBean.java
+++ b/core/src/main/java/org/apache/struts2/components/UIBean.java
@@ -19,6 +19,7 @@
package org.apache.struts2.components;
import org.apache.struts2.config.ConfigurationException;
+import org.apache.struts2.config.ScopedConstantProvider;
import org.apache.struts2.inject.Inject;
import org.apache.struts2.util.TextParseUtil;
import org.apache.struts2.util.ValueStack;
@@ -528,11 +529,17 @@ public abstract class UIBean extends Component {
// dynamic attributes
protected Map<String, Object> dynamicAttributes = new HashMap<>();
+ /** @deprecated no longer read; use {@link #scopedConstantProvider} */
+ @Deprecated(since = "7.5.0", forRemoval = true)
protected String defaultTemplateDir;
+ /** @deprecated no longer read; use {@link #scopedConstantProvider} */
+ @Deprecated(since = "7.5.0", forRemoval = true)
protected String defaultUITheme;
protected String uiThemeExpansionToken;
protected String uiStaticContentPath;
+ protected ScopedConstantProvider scopedConstantProvider;
+
protected TemplateEngineManager templateEngineManager;
protected CspNonceReader cspNonceReader;
@@ -540,16 +547,27 @@ public abstract class UIBean extends Component {
protected HtmlConstraintProvider htmlConstraintProvider;
protected boolean html5ConstraintsEnabled;
- @Inject(StrutsConstants.STRUTS_UI_TEMPLATEDIR)
+ /**
+ * @deprecated no longer read; set {@code struts.ui.templateDir} globally
or per package with {@code <scoped-constant>}
+ */
+ @Deprecated(since = "7.5.0", forRemoval = true)
public void setDefaultTemplateDir(String dir) {
this.defaultTemplateDir = dir;
}
- @Inject(StrutsConstants.STRUTS_UI_THEME)
+ /**
+ * @deprecated no longer read; set {@code struts.ui.theme} globally or per
package with {@code <scoped-constant>}
+ */
+ @Deprecated(since = "7.5.0", forRemoval = true)
public void setDefaultUITheme(String theme) {
this.defaultUITheme = theme;
}
+ @Inject
+ public void setScopedConstantProvider(ScopedConstantProvider
scopedConstantProvider) {
+ this.scopedConstantProvider = scopedConstantProvider;
+ }
+
@Inject(StrutsConstants.STRUTS_UI_THEME_EXPANSION_TOKEN)
public void setUIThemeExpansionToken(String uiThemeExpansionToken) {
this.uiThemeExpansionToken = uiThemeExpansionToken;
@@ -643,7 +661,7 @@ public abstract class UIBean extends Component {
// Default template set
if (isBlank(result)) {
- result = defaultTemplateDir;
+ result =
scopedConstantProvider.getValue(StrutsConstants.STRUTS_UI_TEMPLATEDIR);
}
// Defaults to 'template'
@@ -675,7 +693,7 @@ public abstract class UIBean extends Component {
// Default theme set
if (isBlank(result)) {
- result = defaultUITheme;
+ result =
scopedConstantProvider.getValue(StrutsConstants.STRUTS_UI_THEME);
}
return result;
diff --git
a/core/src/main/java/org/apache/struts2/config/providers/StrutsDefaultConfigurationProvider.java
b/core/src/main/java/org/apache/struts2/config/providers/StrutsDefaultConfigurationProvider.java
index 736af6c91..c8aea1c7b 100644
---
a/core/src/main/java/org/apache/struts2/config/providers/StrutsDefaultConfigurationProvider.java
+++
b/core/src/main/java/org/apache/struts2/config/providers/StrutsDefaultConfigurationProvider.java
@@ -23,9 +23,11 @@ import org.apache.struts2.DefaultActionProxyFactory;
import org.apache.struts2.DefaultUnknownHandlerManager;
import org.apache.struts2.FileManagerFactory;
import org.apache.struts2.UnknownHandlerManager;
+import org.apache.struts2.components.StrutsUiScopableConstants;
import org.apache.struts2.config.Configuration;
import org.apache.struts2.config.ConfigurationException;
import org.apache.struts2.config.ConfigurationProvider;
+import org.apache.struts2.config.ScopableConstants;
import org.apache.struts2.config.ScopedConstantProvider;
import org.apache.struts2.config.impl.DefaultConfiguration;
import org.apache.struts2.conversion.NullHandler;
@@ -132,6 +134,7 @@ public class StrutsDefaultConfigurationProvider implements
ConfigurationProvider
.factory(UnknownHandlerManager.class,
DefaultUnknownHandlerManager.class, Scope.SINGLETON)
.factory(ScopedConstantProvider.class,
StrutsScopedConstantProvider.class, Scope.SINGLETON)
+ .factory(ScopableConstants.class,
StrutsUiScopableConstants.class, Scope.SINGLETON)
// silly workarounds for ognl since there is no way to flush
its caches
.factory(PropertyAccessor.class, List.class.getName(),
XWorkListPropertyAccessor.class, Scope.SINGLETON)
diff --git a/core/src/main/resources/struts-beans.xml
b/core/src/main/resources/struts-beans.xml
index abfca2af6..922dc91d7 100644
--- a/core/src/main/resources/struts-beans.xml
+++ b/core/src/main/resources/struts-beans.xml
@@ -260,6 +260,8 @@
<bean type="org.apache.struts2.config.ScopedConstantProvider" name="struts"
class="org.apache.struts2.config.providers.StrutsScopedConstantProvider"
scope="singleton"/>
+ <bean type="org.apache.struts2.config.ScopableConstants" name="struts"
+ class="org.apache.struts2.components.StrutsUiScopableConstants"
scope="singleton"/>
<bean type="org.apache.struts2.url.QueryStringBuilder"
name="strutsQueryStringBuilder"
class="org.apache.struts2.url.StrutsQueryStringBuilder"
scope="singleton"/>
diff --git
a/core/src/test/java/org/apache/struts2/components/UIBeanScopedConstantsTest.java
b/core/src/test/java/org/apache/struts2/components/UIBeanScopedConstantsTest.java
new file mode 100644
index 000000000..d5800f046
--- /dev/null
+++
b/core/src/test/java/org/apache/struts2/components/UIBeanScopedConstantsTest.java
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.struts2.components;
+
+import org.apache.struts2.ActionContext;
+import org.apache.struts2.ActionSupport;
+import org.apache.struts2.StrutsInternalTestCase;
+import org.apache.struts2.config.entities.ActionConfig;
+import org.apache.struts2.dispatcher.AttributeMap;
+import org.apache.struts2.dispatcher.DispatcherConstants;
+import org.apache.struts2.dispatcher.RequestMap;
+import org.apache.struts2.mock.MockActionInvocation;
+import org.apache.struts2.mock.MockActionProxy;
+import org.apache.struts2.util.ValueStack;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
+
+import java.util.Map;
+
+public class UIBeanScopedConstantsTest extends StrutsInternalTestCase {
+
+ private ValueStack stack;
+ private MockHttpServletRequest request;
+ private MockHttpServletResponse response;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
initDispatcherWithConfigs("struts-default.xml,org/apache/struts2/components/struts-scoped-ui.xml");
+ stack = ActionContext.getContext().getValueStack();
+ request = new MockHttpServletRequest();
+ response = new MockHttpServletResponse();
+ }
+
+ public void testPackageOverrideIsUsedWithoutTagAttribute() {
+ enterPackage("admin");
+
+ TextField txtFld = newTextField();
+
+ assertEquals("css_xhtml", txtFld.getTheme());
+ assertEquals("admin-template", txtFld.getTemplateDir());
+ }
+
+ public void testChildPackageInheritsOverride() {
+ enterPackage("adminChild");
+
+ TextField txtFld = newTextField();
+
+ assertEquals("css_xhtml", txtFld.getTheme());
+ assertEquals("admin-template", txtFld.getTemplateDir());
+ }
+
+ public void testGlobalValueWithoutOverride() {
+ enterPackage("plain");
+
+ TextField txtFld = newTextField();
+
+ assertEquals("xhtml", txtFld.getTheme());
+ assertEquals("template", txtFld.getTemplateDir());
+ }
+
+ public void testGlobalValueWithoutInvocation() {
+ TextField txtFld = newTextField();
+
+ assertEquals("xhtml", txtFld.getTheme());
+ assertEquals("template", txtFld.getTemplateDir());
+ }
+
+ public void testTagAttributeWinsOverPackageOverride() {
+ enterPackage("admin");
+
+ TextField txtFld = newTextField();
+ txtFld.setTheme("simple");
+ txtFld.setTemplateDir("tag-template");
+
+ assertEquals("simple", txtFld.getTheme());
+ assertEquals("tag-template", txtFld.getTemplateDir());
+ }
+
+ public void testFormThemeWinsOverPackageOverride() {
+ enterPackage("admin");
+
+ Form form = new Form(stack, request, response);
+ container.inject(form);
+ form.setTheme("simple");
+
+ assertEquals("simple", newTextField().getTheme());
+ }
+
+ public void testScopeAttributeWinsOverPackageOverride() {
+ enterPackage("admin");
+ request.setAttribute("theme", "simple");
+ request.setAttribute("templateDir", "attr-template");
+ Map<String, Object> context = stack.getContext();
+ context.put(DispatcherConstants.REQUEST, new RequestMap(request));
+ context.put("attr", new AttributeMap(context));
+
+ TextField txtFld = newTextField();
+
+ assertEquals("simple", txtFld.getTheme());
+ assertEquals("attr-template", txtFld.getTemplateDir());
+ }
+
+ private TextField newTextField() {
+ TextField txtFld = new TextField(stack, request, response);
+ container.inject(txtFld);
+ return txtFld;
+ }
+
+ private void enterPackage(String packageName) {
+ MockActionProxy proxy = new MockActionProxy();
+ proxy.setConfig(new ActionConfig.Builder(packageName, "test",
ActionSupport.class.getName()).build());
+ MockActionInvocation invocation = new MockActionInvocation();
+ invocation.setProxy(proxy);
+ ActionContext.getContext().withActionInvocation(invocation);
+ }
+}
diff --git a/core/src/test/java/org/apache/struts2/components/UIBeanTest.java
b/core/src/test/java/org/apache/struts2/components/UIBeanTest.java
index cc194bd08..41b19575c 100644
--- a/core/src/test/java/org/apache/struts2/components/UIBeanTest.java
+++ b/core/src/test/java/org/apache/struts2/components/UIBeanTest.java
@@ -183,6 +183,7 @@ public class UIBeanTest extends StrutsInternalTestCase {
MockHttpServletResponse res = new MockHttpServletResponse();
TextField txtFld = new TextField(stack, req, res);
+ container.inject(txtFld);
Template defaultTemplate = txtFld.buildTemplateName(null,
defaultTemplateName);
Template customTemplate = txtFld.buildTemplateName(customTemplateName,
defaultTemplateName);
@@ -203,7 +204,7 @@ public class UIBeanTest extends StrutsInternalTestCase {
TextField txtFld = new TextField(stack, req, res);
txtFld.setTemplateDir(explicitTemplateDir);
- txtFld.setDefaultTemplateDir(defaultTemplateDir);
+ txtFld.setScopedConstantProvider(name -> defaultTemplateDir);
assertEquals(explicitTemplateDir, txtFld.getTemplateDir());
}
@@ -215,7 +216,7 @@ public class UIBeanTest extends StrutsInternalTestCase {
MockHttpServletResponse res = new MockHttpServletResponse();
TextField txtFld = new TextField(stack, req, res);
- txtFld.setDefaultTemplateDir(defaultTemplateDir);
+ txtFld.setScopedConstantProvider(name -> defaultTemplateDir);
assertEquals(defaultTemplateDir, txtFld.getTemplateDir());
}
@@ -226,6 +227,7 @@ public class UIBeanTest extends StrutsInternalTestCase {
MockHttpServletResponse res = new MockHttpServletResponse();
TextField txtFld = new TextField(stack, req, res);
+ txtFld.setScopedConstantProvider(name -> null);
assertEquals("template", txtFld.getTemplateDir());
}
diff --git
a/core/src/test/java/org/apache/struts2/config/ScopedConstantsValidationTest.java
b/core/src/test/java/org/apache/struts2/config/ScopedConstantsValidationTest.java
index 59dfedc02..78b6163db 100644
---
a/core/src/test/java/org/apache/struts2/config/ScopedConstantsValidationTest.java
+++
b/core/src/test/java/org/apache/struts2/config/ScopedConstantsValidationTest.java
@@ -19,8 +19,14 @@
package org.apache.struts2.config;
import org.apache.struts2.ActionContext;
+import org.apache.struts2.FileManagerFactory;
+import org.apache.struts2.config.impl.DefaultConfiguration;
import org.apache.struts2.config.providers.StrutsDefaultConfigurationProvider;
import org.apache.struts2.inject.Container;
+import org.apache.struts2.inject.ContainerBuilder;
+import org.apache.struts2.inject.Scope;
+import org.apache.struts2.util.fs.DefaultFileManagerFactory;
+import org.apache.struts2.util.location.LocatableProperties;
import org.junit.After;
import org.junit.Test;
@@ -49,12 +55,20 @@ public class ScopedConstantsValidationTest {
.isEqualTo(Map.of("sample.scopable", "x"));
}
+ @Test
+ public void uiThemeAndTemplateDirAreScopable() {
+ Configuration configuration = load("struts-scoped-constants-ui.xml");
+
+ assertThat(configuration.getPackageConfig("ui").getScopedConstants())
+ .isEqualTo(Map.of("struts.ui.theme", "css_xhtml",
"struts.ui.templateDir", "admin-template"));
+ }
+
@Test
public void unregisteredNameFails() {
assertThatThrownBy(() ->
load("struts-scoped-constants-unregistered.xml"))
.isInstanceOf(ConfigurationException.class)
.hasStackTraceContaining("Package [unregistered] declares
scoped constant [sample.unknown], which is not scopable. "
- + "Scopable constants: [sample.scopable,
sample.unset].");
+ + "Scopable constants: [sample.scopable, sample.unset,
struts.ui.templateDir, struts.ui.theme].");
}
@Test
@@ -66,7 +80,7 @@ public class ScopedConstantsValidationTest {
@Test
public void anyScopedConstantFailsWhenNothingIsScopable() {
- assertThatThrownBy(() ->
load("struts-scoped-constants-no-registry.xml"))
+ assertThatThrownBy(() ->
loadWithBootstrapBeansOnly("struts-scoped-constants-no-registry.xml"))
.isInstanceOf(ConfigurationException.class)
.hasStackTraceContaining("Package [unregistered] declares
scoped constant [sample.scopable], which is not scopable. "
+ "No constants are scopable in this configuration.");
@@ -86,4 +100,18 @@ public class ScopedConstantsValidationTest {
configurationManager.addContainerProvider(new
StrutsXmlConfigurationProvider("org/apache/struts2/config/" + fixture));
return configurationManager.getConfiguration();
}
+
+ private Configuration loadWithBootstrapBeansOnly(String fixture) {
+ configurationManager = new
ConfigurationManager(Container.DEFAULT_NAME);
+ configurationManager.addContainerProvider(new
StrutsDefaultConfigurationProvider() {
+ @Override
+ public void register(ContainerBuilder builder, LocatableProperties
props) {
+ DefaultConfiguration.bootstrapFactories(builder)
+ .factory(FileManagerFactory.class,
DefaultFileManagerFactory.class, Scope.SINGLETON);
+ DefaultConfiguration.BOOTSTRAP_CONSTANTS.forEach((name, value)
-> props.setProperty(name, String.valueOf(value)));
+ }
+ });
+ configurationManager.addContainerProvider(new
StrutsXmlConfigurationProvider("org/apache/struts2/config/" + fixture));
+ return configurationManager.getConfiguration();
+ }
}
diff --git
a/core/src/test/resources/org/apache/struts2/components/struts-scoped-ui.xml
b/core/src/test/resources/org/apache/struts2/components/struts-scoped-ui.xml
new file mode 100644
index 000000000..a156ba7af
--- /dev/null
+++ b/core/src/test/resources/org/apache/struts2/components/struts-scoped-ui.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+-->
+<!DOCTYPE struts PUBLIC
+ "-//Apache Software Foundation//DTD Struts Configuration 7.5//EN"
+ "struts-7.5.dtd">
+<struts>
+ <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>
+
+ <package name="adminChild" extends="admin" namespace="/admin/child"/>
+
+ <package name="plain" extends="struts-default" namespace="/plain"/>
+</struts>
diff --git
a/core/src/test/resources/org/apache/struts2/config/struts-scoped-constants-ui.xml
b/core/src/test/resources/org/apache/struts2/config/struts-scoped-constants-ui.xml
new file mode 100644
index 000000000..c1ca79b0d
--- /dev/null
+++
b/core/src/test/resources/org/apache/struts2/config/struts-scoped-constants-ui.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+-->
+<!DOCTYPE struts PUBLIC
+ "-//Apache Software Foundation//DTD Struts Configuration 7.5//EN"
+ "struts-7.5.dtd">
+<struts>
+ <package name="ui" namespace="/ui">
+ <scoped-constant name="struts.ui.theme" value="css_xhtml"/>
+ <scoped-constant name="struts.ui.templateDir" value="admin-template"/>
+ </package>
+</struts>
diff --git
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ActionErrorTest.java
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ActionErrorTest.java
index 9129f24bc..5fef5f66c 100644
---
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ActionErrorTest.java
+++
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ActionErrorTest.java
@@ -75,6 +75,7 @@ public class ActionErrorTest extends AbstractTest {
super.setUp();
this.tag = new ActionError(stack, request, response);
this.tag.setCspNonceReader(new
StrutsCspNonceReader(CspNonceSource.SESSION.name()));
+ this.tag.setScopedConstantProvider(name -> null);
}
@Override
diff --git
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ActionMessageTest.java
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ActionMessageTest.java
index 8d8895372..450262b78 100644
---
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ActionMessageTest.java
+++
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ActionMessageTest.java
@@ -75,6 +75,7 @@ public class ActionMessageTest extends AbstractTest {
super.setUp();
this.tag = new ActionError(stack, request, response);
this.tag.setCspNonceReader(new
StrutsCspNonceReader(CspNonceSource.SESSION.name()));
+ this.tag.setScopedConstantProvider(name -> null);
}
@Override
diff --git
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/AnchorTest.java
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/AnchorTest.java
index d7512ccd3..8cd4baeb2 100644
---
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/AnchorTest.java
+++
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/AnchorTest.java
@@ -114,6 +114,7 @@ public class AnchorTest extends AbstractTest {
this.tag.setUrlRenderer(new ServletUrlRenderer());
this.tag.setNotExcludedAcceptedPatterns(new
DefaultNotExcludedAcceptedPatternsChecker());
this.tag.setCspNonceReader(new
StrutsCspNonceReader(CspNonceSource.SESSION.name()));
+ this.tag.setScopedConstantProvider(name -> null);
}
@Override
diff --git
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/CheckboxTest.java
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/CheckboxTest.java
index acc811704..efd4e1dbf 100644
---
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/CheckboxTest.java
+++
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/CheckboxTest.java
@@ -93,6 +93,7 @@ public class CheckboxTest extends
AbstractCommonAttributesTest {
tag = new Checkbox(stack, request, response);
tag.setNotExcludedAcceptedPatterns(new
DefaultNotExcludedAcceptedPatternsChecker());
this.tag.setCspNonceReader(new
StrutsCspNonceReader(CspNonceSource.SESSION.name()));
+ this.tag.setScopedConstantProvider(name -> null);
}
@Override
diff --git
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/DateTextFieldTest.java
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/DateTextFieldTest.java
index 7b1d36069..1cc501441 100644
---
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/DateTextFieldTest.java
+++
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/DateTextFieldTest.java
@@ -59,6 +59,7 @@ public class DateTextFieldTest extends
AbstractCommonAttributesTest {
super.setUp();
this.tag = new DateTextField(stack, request, response);
this.tag.setCspNonceReader(new
StrutsCspNonceReader(CspNonceSource.SESSION.name()));
+ this.tag.setScopedConstantProvider(name -> null);
}
@Override
diff --git
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FieldErrorTest.java
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FieldErrorTest.java
index fca239293..686fe047a 100644
---
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FieldErrorTest.java
+++
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FieldErrorTest.java
@@ -103,6 +103,7 @@ public class FieldErrorTest extends AbstractTest {
super.setUp();
this.tag = new FieldError(stack, request, response);
this.tag.setCspNonceReader(new
StrutsCspNonceReader(CspNonceSource.SESSION.name()));
+ this.tag.setScopedConstantProvider(name -> null);
}
@Override
diff --git
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FileTest.java
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FileTest.java
index dce590b30..23cf749bd 100644
---
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FileTest.java
+++
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FileTest.java
@@ -53,6 +53,7 @@ public class FileTest extends AbstractCommonAttributesTest {
super.setUp();
this.tag = new File(stack, request, response);
this.tag.setCspNonceReader(new
StrutsCspNonceReader(CspNonceSource.SESSION.name()));
+ this.tag.setScopedConstantProvider(name -> null);
}
@Override
diff --git
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FormTest.java
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FormTest.java
index 9ee9c9152..b37ae6e0e 100644
---
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FormTest.java
+++
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FormTest.java
@@ -83,5 +83,6 @@ public class FormTest extends AbstractCommonAttributesTest {
EasyMock.replay(renderer);
tag.setUrlRenderer(renderer);
this.tag.setCspNonceReader(new
StrutsCspNonceReader(CspNonceSource.SESSION.name()));
+ this.tag.setScopedConstantProvider(name -> null);
}
}
diff --git
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/HeadTest.java
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/HeadTest.java
index ace29fdbc..384f162e9 100644
---
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/HeadTest.java
+++
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/HeadTest.java
@@ -42,6 +42,7 @@ public class HeadTest extends AbstractTest {
super.setUp();
this.tag = new Head(stack, request, response);
this.tag.setCspNonceReader(new
StrutsCspNonceReader(CspNonceSource.SESSION.name()));
+ this.tag.setScopedConstantProvider(name -> null);
}
@Override
diff --git
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/HiddenTest.java
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/HiddenTest.java
index c517a62e8..4bcb21fb0 100644
---
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/HiddenTest.java
+++
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/HiddenTest.java
@@ -52,6 +52,7 @@ public class HiddenTest extends AbstractTest {
super.setUp();
this.tag = new Hidden(stack, request, response);
this.tag.setCspNonceReader(new
StrutsCspNonceReader(CspNonceSource.SESSION.name()));
+ this.tag.setScopedConstantProvider(name -> null);
}
@Override
diff --git
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/LabelTest.java
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/LabelTest.java
index 90cda064c..b897d956e 100644
---
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/LabelTest.java
+++
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/LabelTest.java
@@ -51,6 +51,7 @@ public class LabelTest extends AbstractCommonAttributesTest {
super.setUp();
this.tag = new Label(stack, request, response);
this.tag.setCspNonceReader(new
StrutsCspNonceReader(CspNonceSource.SESSION.name()));
+ this.tag.setScopedConstantProvider(name -> null);
}
@Override
diff --git
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/LinkTest.java
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/LinkTest.java
index 69c1a11bb..f12d2878a 100644
---
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/LinkTest.java
+++
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/LinkTest.java
@@ -106,5 +106,6 @@ public class LinkTest extends AbstractTest {
super.setUp();
this.tag = new Link(stack, request, response);
this.tag.setCspNonceReader(new
StrutsCspNonceReader(CspNonceSource.SESSION.name()));
+ this.tag.setScopedConstantProvider(name -> null);
}
}
diff --git
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/PasswordTest.java
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/PasswordTest.java
index ca12ff316..e941a6612 100644
---
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/PasswordTest.java
+++
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/PasswordTest.java
@@ -74,6 +74,7 @@ public class PasswordTest extends
AbstractCommonAttributesTest {
super.setUp();
this.tag = new Password(stack, request, response);
this.tag.setCspNonceReader(new
StrutsCspNonceReader(CspNonceSource.SESSION.name()));
+ this.tag.setScopedConstantProvider(name -> null);
}
@Override
diff --git
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ResetTest.java
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ResetTest.java
index 14464145f..6ef1cc8fe 100644
---
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ResetTest.java
+++
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ResetTest.java
@@ -72,6 +72,7 @@ public class ResetTest extends AbstractCommonAttributesTest {
super.setUp();
this.tag = new Reset(stack, request, response);
this.tag.setCspNonceReader(new
StrutsCspNonceReader(CspNonceSource.SESSION.name()));
+ this.tag.setScopedConstantProvider(name -> null);
}
@Override
diff --git
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ScriptTest.java
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ScriptTest.java
index ad042e964..f35ad883c 100644
---
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ScriptTest.java
+++
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ScriptTest.java
@@ -75,5 +75,6 @@ public class ScriptTest extends AbstractTest {
this.tag = new Script(stack, request, response);
tag.setNotExcludedAcceptedPatterns(new
DefaultNotExcludedAcceptedPatternsChecker());
this.tag.setCspNonceReader(new
StrutsCspNonceReader(CspNonceSource.SESSION.name()));
+ this.tag.setScopedConstantProvider(name -> null);
}
}
diff --git
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/SelectTest.java
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/SelectTest.java
index 441d4e152..aecf22c7b 100644
---
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/SelectTest.java
+++
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/SelectTest.java
@@ -117,6 +117,7 @@ public class SelectTest extends
AbstractCommonAttributesTest {
super.setUp();
this.tag = new Select(stack, request, response);
this.tag.setCspNonceReader(new
StrutsCspNonceReader(CspNonceSource.SESSION.name()));
+ this.tag.setScopedConstantProvider(name -> null);
}
@Override
diff --git
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/SubmitTest.java
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/SubmitTest.java
index 4760bcc5c..d3b8b87ef 100644
---
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/SubmitTest.java
+++
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/SubmitTest.java
@@ -157,6 +157,7 @@ public class SubmitTest extends
AbstractCommonAttributesTest {
super.setUp();
this.tag = new Submit(stack, request, response);
this.tag.setCspNonceReader(new
StrutsCspNonceReader(CspNonceSource.SESSION.name()));
+ this.tag.setScopedConstantProvider(name -> null);
}
@Override
diff --git
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TextAreaTest.java
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TextAreaTest.java
index 08d08caba..6aab92dab 100644
---
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TextAreaTest.java
+++
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TextAreaTest.java
@@ -74,6 +74,7 @@ public class TextAreaTest extends
AbstractCommonAttributesTest {
super.setUp();
this.tag = new TextArea(stack, request, response);
this.tag.setCspNonceReader(new
StrutsCspNonceReader(CspNonceSource.SESSION.name()));
+ this.tag.setScopedConstantProvider(name -> null);
}
@Override
diff --git
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TextFieldTest.java
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TextFieldTest.java
index 331442f13..e4b77b66e 100644
---
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TextFieldTest.java
+++
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TextFieldTest.java
@@ -55,6 +55,7 @@ public class TextFieldTest extends
AbstractCommonAttributesTest {
super.setUp();
this.tag = new TextField(stack, request, response);
this.tag.setCspNonceReader(new
StrutsCspNonceReader(CspNonceSource.SESSION.name()));
+ this.tag.setScopedConstantProvider(name -> null);
}
@Override
diff --git
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TokenTest.java
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TokenTest.java
index 4680e2bb1..cc28e0a55 100644
---
a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TokenTest.java
+++
b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TokenTest.java
@@ -52,6 +52,7 @@ public class TokenTest extends AbstractTest {
super.setUp();
this.tag = new Token(stack, request, response);
this.tag.setCspNonceReader(new
StrutsCspNonceReader(CspNonceSource.SESSION.name()));
+ this.tag.setScopedConstantProvider(name -> null);
ActionContext.of()
.withSession(new HashMap<>())