From e2ec114577ec2368a03bd462cc060d30f610cb31 Mon Sep 17 00:00:00 2001 From: Jeffery Xie Date: Tue, 9 Apr 2024 15:33:10 +1000 Subject: [PATCH 1/3] WW-5408 add option to not fallback to empty namespace when unresolved --- .../opensymphony/xwork2/XWorkTestCase.java | 35 +++++++++++++++--- .../config/impl/DefaultConfiguration.java | 13 ++++--- .../org/apache/struts2/StrutsConstants.java | 2 ++ .../config/entities/ConstantConfig.java | 10 ++++++ .../xwork2/config/ConfigurationTest.java | 36 +++++++++++++++++++ .../struts2/views/jsp/ui/DebugTagTest.java | 22 +++--------- 6 files changed, 91 insertions(+), 27 deletions(-) diff --git a/core/src/main/java/com/opensymphony/xwork2/XWorkTestCase.java b/core/src/main/java/com/opensymphony/xwork2/XWorkTestCase.java index 88790fc6f7..8a4695e576 100644 --- a/core/src/main/java/com/opensymphony/xwork2/XWorkTestCase.java +++ b/core/src/main/java/com/opensymphony/xwork2/XWorkTestCase.java @@ -36,6 +36,8 @@ import java.util.Locale; import java.util.Map; +import static java.util.Collections.singletonMap; + /** * Base JUnit TestCase to extend for XWork specific JUnit tests. Uses * the generic test setup for logic. @@ -56,9 +58,7 @@ public XWorkTestCase() { @Override protected void setUp() throws Exception { configurationManager = XWorkTestCaseHelper.setUp(); - configuration = configurationManager.getConfiguration(); - container = configuration.getContainer(); - actionProxyFactory = container.getInstance(ActionProxyFactory.class); + reloadConfiguration(configurationManager); } @Override @@ -66,13 +66,17 @@ protected void tearDown() throws Exception { XWorkTestCaseHelper.tearDown(configurationManager); } - protected void loadConfigurationProviders(ConfigurationProvider... providers) { - configurationManager = XWorkTestCaseHelper.loadConfigurationProviders(configurationManager, providers); + private void reloadConfiguration(ConfigurationManager configurationManager) { configuration = configurationManager.getConfiguration(); container = configuration.getContainer(); actionProxyFactory = container.getInstance(ActionProxyFactory.class); } + protected void loadConfigurationProviders(ConfigurationProvider... providers) { + configurationManager = XWorkTestCaseHelper.loadConfigurationProviders(configurationManager, providers); + reloadConfiguration(configurationManager); + } + protected void loadButSet(Map properties) { loadConfigurationProviders(new StubConfigurationProvider() { @Override @@ -115,4 +119,25 @@ protected Map createContextWithLocale(Locale locale) { .getContextMap(); } + protected void setStrutsConstant(String constant, String value) { + setStrutsConstant(singletonMap(constant, value)); + } + + protected void setStrutsConstant(final Map overwritePropeties) { + configurationManager.addContainerProvider(new StubConfigurationProvider() { + @Override + public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException { + for (Map.Entry stringStringEntry : overwritePropeties.entrySet()) { + props.setProperty(stringStringEntry.getKey(), stringStringEntry.getValue(), null); + } + } + + @Override + public void destroy() { + } + }); + + configurationManager.reload(); + reloadConfiguration(configurationManager); + } } diff --git a/core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java b/core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java index 7bf0e7c779..c1851c5ea5 100644 --- a/core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java +++ b/core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java @@ -459,9 +459,12 @@ protected synchronized RuntimeConfiguration buildRuntimeConfiguration() throws C boolean appendNamedParameters = Boolean.parseBoolean( container.getInstance(String.class, StrutsConstants.STRUTS_MATCHER_APPEND_NAMED_PARAMETERS) ); + boolean emptyNamespaceFallbackDisabled = Boolean.parseBoolean( + container.getInstance(String.class, StrutsConstants.STRUTS_DISABLE_EMPTY_NAMESPACE_FALLBACK) + ); return new RuntimeConfigurationImpl(Collections.unmodifiableMap(namespaceActionConfigs), - Collections.unmodifiableMap(namespaceConfigs), matcher, appendNamedParameters); + Collections.unmodifiableMap(namespaceConfigs), matcher, appendNamedParameters, emptyNamespaceFallbackDisabled); } private void setDefaultResults(Map results, PackageConfig packageContext) { @@ -536,14 +539,17 @@ private static class RuntimeConfigurationImpl implements RuntimeConfiguration { private final Map namespaceActionConfigMatchers; private final NamespaceMatcher namespaceMatcher; private final Map namespaceConfigs; + private final boolean emptyNamespaceFallbackDisabled; public RuntimeConfigurationImpl(Map> namespaceActionConfigs, Map namespaceConfigs, PatternMatcher matcher, - boolean appendNamedParameters) + boolean appendNamedParameters, + boolean emptyNamespaceFallbackDisabled) { this.namespaceActionConfigs = namespaceActionConfigs; this.namespaceConfigs = namespaceConfigs; + this.emptyNamespaceFallbackDisabled = emptyNamespaceFallbackDisabled; this.namespaceActionConfigMatchers = new LinkedHashMap<>(); this.namespaceMatcher = new NamespaceMatcher(matcher, namespaceActionConfigs.keySet(), appendNamedParameters); @@ -583,11 +589,10 @@ public ActionConfig getActionConfig(String namespace, String name) { } // fail over to empty namespace - if (config == null && StringUtils.isNotBlank(namespace)) { + if (config == null && StringUtils.isNotBlank(namespace) && ("/".equals(namespace) || !emptyNamespaceFallbackDisabled)) { config = findActionConfigInNamespace("", name); } - return config; } diff --git a/core/src/main/java/org/apache/struts2/StrutsConstants.java b/core/src/main/java/org/apache/struts2/StrutsConstants.java index 3d0d1a00dc..b5e19a415e 100644 --- a/core/src/main/java/org/apache/struts2/StrutsConstants.java +++ b/core/src/main/java/org/apache/struts2/StrutsConstants.java @@ -230,6 +230,8 @@ public final class StrutsConstants { public static final String STRUTS_XWORKCONVERTER = "struts.xworkConverter"; public static final String STRUTS_ALWAYS_SELECT_FULL_NAMESPACE = "struts.mapper.alwaysSelectFullNamespace"; + /** Disable fallback to empty namespace when request namespace didn't match any in action configuration */ + public static final String STRUTS_DISABLE_EMPTY_NAMESPACE_FALLBACK = "struts.disableActionConfigFallbackToEmptyNamespace"; /** The {@link com.opensymphony.xwork2.LocaleProviderFactory} implementation class */ public static final String STRUTS_LOCALE_PROVIDER_FACTORY = "struts.localeProviderFactory"; diff --git a/core/src/main/java/org/apache/struts2/config/entities/ConstantConfig.java b/core/src/main/java/org/apache/struts2/config/entities/ConstantConfig.java index 2b854243dc..b7d4626095 100644 --- a/core/src/main/java/org/apache/struts2/config/entities/ConstantConfig.java +++ b/core/src/main/java/org/apache/struts2/config/entities/ConstantConfig.java @@ -90,6 +90,7 @@ public class ConstantConfig { private Boolean freemarkerWrapperAltMap; private BeanConfig xworkConverter; private Boolean mapperAlwaysSelectFullNamespace; + private Boolean proxyDisableEmptyNamespaceFallback; private BeanConfig localeProviderFactory; private String mapperIdParameterName; private Boolean ognlAllowStaticFieldAccess; @@ -225,6 +226,7 @@ public Map getAllAsStringsMap() { map.put(StrutsConstants.STRUTS_FREEMARKER_WRAPPER_ALT_MAP, Objects.toString(freemarkerWrapperAltMap, null)); map.put(StrutsConstants.STRUTS_XWORKCONVERTER, beanConfToString(xworkConverter)); map.put(StrutsConstants.STRUTS_ALWAYS_SELECT_FULL_NAMESPACE, Objects.toString(mapperAlwaysSelectFullNamespace, null)); + map.put(StrutsConstants.STRUTS_DISABLE_EMPTY_NAMESPACE_FALLBACK, Objects.toString(proxyDisableEmptyNamespaceFallback, null)); map.put(StrutsConstants.STRUTS_LOCALE_PROVIDER_FACTORY, beanConfToString(localeProviderFactory)); map.put(StrutsConstants.STRUTS_ID_PARAMETER_NAME, mapperIdParameterName); map.put(StrutsConstants.STRUTS_ALLOW_STATIC_FIELD_ACCESS, Objects.toString(ognlAllowStaticFieldAccess, null)); @@ -812,6 +814,14 @@ public void setMapperAlwaysSelectFullNamespace(Boolean mapperAlwaysSelectFullNam this.mapperAlwaysSelectFullNamespace = mapperAlwaysSelectFullNamespace; } + public Boolean getProxyDisableEmptyNamespaceFallback() { + return proxyDisableEmptyNamespaceFallback; + } + + public void setProxyDisableEmptyNamespaceFallback(Boolean proxyDisableEmptyNamespaceFallback) { + this.proxyDisableEmptyNamespaceFallback = proxyDisableEmptyNamespaceFallback; + } + public BeanConfig getLocaleProviderFactory() { return localeProviderFactory; } diff --git a/core/src/test/java/com/opensymphony/xwork2/config/ConfigurationTest.java b/core/src/test/java/com/opensymphony/xwork2/config/ConfigurationTest.java index b52b9d48ca..8b9b36618d 100644 --- a/core/src/test/java/com/opensymphony/xwork2/config/ConfigurationTest.java +++ b/core/src/test/java/com/opensymphony/xwork2/config/ConfigurationTest.java @@ -31,6 +31,7 @@ import com.opensymphony.xwork2.mock.MockInterceptor; import com.opensymphony.xwork2.test.StubConfigurationProvider; import com.opensymphony.xwork2.util.location.LocatableProperties; +import org.apache.struts2.StrutsConstants; import org.apache.struts2.config.StrutsXmlConfigurationProvider; import org.apache.struts2.dispatcher.HttpParameters; @@ -239,6 +240,41 @@ public void testMultipleContainerProviders() { mockContainerProvider.verify(); } + public void testGetActionConfigFallbackToEmptyNamespaceWhenNamespaceDontMatchAndEmptyNamespaceFallbackIsNotDisabled() { + // struts.disableEmptyNamespaceFallback default to null, so it's not disabled + RuntimeConfiguration configuration = configurationManager.getConfiguration().getRuntimeConfiguration(); + + // check namespace that doesn't match fallback to empty namespace + ActionConfig actionConfig = configuration.getActionConfig("/something/that/is/not/in/the/namespace/config", "LazyFoo"); + assertEquals("default", actionConfig.getPackageName()); // fallback to empty namespace (package name is default) + assertEquals("LazyFoo", actionConfig.getName()); + + // check non-empty namespace and name in config still matches + assertNotNull(configuration.getActionConfig("includeTest", "Foo")); + + // check root namespace and name in config still matches + actionConfig = configuration.getActionConfig("/", "LazyFoo"); + assertEquals("default", actionConfig.getPackageName()); + assertEquals("LazyFoo", actionConfig.getName()); + } + + public void testGetActionConfigReturnNullWhenNamespaceDontMatchAndEmptyNamespaceFallbackIsDisabled() { + // set the struts.disableEmptyNamespaceFallback to true and reload the configuration + setStrutsConstant(StrutsConstants.STRUTS_DISABLE_EMPTY_NAMESPACE_FALLBACK, "true"); + RuntimeConfiguration configuration = configurationManager.getConfiguration().getRuntimeConfiguration(); + + // check namespace that doesn't match NOT fallback to empty namespace and return null + assertNull(configuration.getActionConfig("/something/that/is/not/in/the/namespace/config", "LazyFoo")); + + // check non-empty namespace and name in config still matches + assertNotNull(configuration.getActionConfig("includeTest", "Foo")); + + // check root namespace and name in config still matches + ActionConfig actionConfig = configuration.getActionConfig("/", "LazyFoo"); + assertEquals("default", actionConfig.getPackageName()); + assertEquals("LazyFoo", actionConfig.getName()); + } + public void testInitForPackageProviders() { loadConfigurationProviders(new StubConfigurationProvider() { diff --git a/core/src/test/java/org/apache/struts2/views/jsp/ui/DebugTagTest.java b/core/src/test/java/org/apache/struts2/views/jsp/ui/DebugTagTest.java index 7f4b545819..b7db51513b 100644 --- a/core/src/test/java/org/apache/struts2/views/jsp/ui/DebugTagTest.java +++ b/core/src/test/java/org/apache/struts2/views/jsp/ui/DebugTagTest.java @@ -217,23 +217,9 @@ private void setDevMode(final boolean devMode) { /** * Overwrite the Struts Constant and reload container */ - private void setStrutsConstant(final Map overwritePropeties) { - configurationManager.addContainerProvider(new StubConfigurationProvider() { - @Override - public boolean needsReload() { - return true; - } - - @Override - public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException { - for (Map.Entry stringStringEntry : overwritePropeties.entrySet()) { - props.setProperty(stringStringEntry.getKey(), stringStringEntry.getValue(), null); - } - } - }); - - configurationManager.reload(); - container = configurationManager.getConfiguration().getContainer(); + @Override + protected void setStrutsConstant(final Map overwritePropeties) { + super.setStrutsConstant(overwritePropeties); stack.getActionContext().withContainer(container); } -} \ No newline at end of file +} From f9f63275701bb3aeee9ec8b6278a1677bc3f20c4 Mon Sep 17 00:00:00 2001 From: Jeffery Xie Date: Wed, 10 Apr 2024 17:30:02 +1000 Subject: [PATCH 2/3] /WW-5408 rename struts.disableActionConfigFallbackToEmptyNamespace to struts.actionConfig.fallbackToEmptyNamespace --- .../xwork2/config/impl/DefaultConfiguration.java | 15 ++++++++------- .../java/org/apache/struts2/StrutsConstants.java | 4 ++-- .../struts2/config/entities/ConstantConfig.java | 12 ++++++------ .../xwork2/config/ConfigurationTest.java | 8 ++++---- 4 files changed, 20 insertions(+), 19 deletions(-) diff --git a/core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java b/core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java index c1851c5ea5..b0d7be13eb 100644 --- a/core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java +++ b/core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java @@ -120,6 +120,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; @@ -459,12 +460,12 @@ protected synchronized RuntimeConfiguration buildRuntimeConfiguration() throws C boolean appendNamedParameters = Boolean.parseBoolean( container.getInstance(String.class, StrutsConstants.STRUTS_MATCHER_APPEND_NAMED_PARAMETERS) ); - boolean emptyNamespaceFallbackDisabled = Boolean.parseBoolean( - container.getInstance(String.class, StrutsConstants.STRUTS_DISABLE_EMPTY_NAMESPACE_FALLBACK) + boolean fallbackToEmptyNamespace = Boolean.parseBoolean( + Optional.ofNullable(container.getInstance(String.class, StrutsConstants.STRUTS_ACTION_CONFIG_FALLBACK_TO_EMPTY_NAMESPACE)).orElse("true") ); return new RuntimeConfigurationImpl(Collections.unmodifiableMap(namespaceActionConfigs), - Collections.unmodifiableMap(namespaceConfigs), matcher, appendNamedParameters, emptyNamespaceFallbackDisabled); + Collections.unmodifiableMap(namespaceConfigs), matcher, appendNamedParameters, fallbackToEmptyNamespace); } private void setDefaultResults(Map results, PackageConfig packageContext) { @@ -539,17 +540,17 @@ private static class RuntimeConfigurationImpl implements RuntimeConfiguration { private final Map namespaceActionConfigMatchers; private final NamespaceMatcher namespaceMatcher; private final Map namespaceConfigs; - private final boolean emptyNamespaceFallbackDisabled; + private final boolean fallbackToEmptyNamespace; public RuntimeConfigurationImpl(Map> namespaceActionConfigs, Map namespaceConfigs, PatternMatcher matcher, boolean appendNamedParameters, - boolean emptyNamespaceFallbackDisabled) + boolean fallbackToEmptyNamespace) { this.namespaceActionConfigs = namespaceActionConfigs; this.namespaceConfigs = namespaceConfigs; - this.emptyNamespaceFallbackDisabled = emptyNamespaceFallbackDisabled; + this.fallbackToEmptyNamespace = fallbackToEmptyNamespace; this.namespaceActionConfigMatchers = new LinkedHashMap<>(); this.namespaceMatcher = new NamespaceMatcher(matcher, namespaceActionConfigs.keySet(), appendNamedParameters); @@ -589,7 +590,7 @@ public ActionConfig getActionConfig(String namespace, String name) { } // fail over to empty namespace - if (config == null && StringUtils.isNotBlank(namespace) && ("/".equals(namespace) || !emptyNamespaceFallbackDisabled)) { + if (config == null && StringUtils.isNotBlank(namespace) && ("/".equals(namespace) || fallbackToEmptyNamespace)) { config = findActionConfigInNamespace("", name); } diff --git a/core/src/main/java/org/apache/struts2/StrutsConstants.java b/core/src/main/java/org/apache/struts2/StrutsConstants.java index b5e19a415e..7a7f4b2478 100644 --- a/core/src/main/java/org/apache/struts2/StrutsConstants.java +++ b/core/src/main/java/org/apache/struts2/StrutsConstants.java @@ -230,8 +230,8 @@ public final class StrutsConstants { public static final String STRUTS_XWORKCONVERTER = "struts.xworkConverter"; public static final String STRUTS_ALWAYS_SELECT_FULL_NAMESPACE = "struts.mapper.alwaysSelectFullNamespace"; - /** Disable fallback to empty namespace when request namespace didn't match any in action configuration */ - public static final String STRUTS_DISABLE_EMPTY_NAMESPACE_FALLBACK = "struts.disableActionConfigFallbackToEmptyNamespace"; + /** Fallback to empty namespace when request namespace didn't match any in action configuration */ + public static final String STRUTS_ACTION_CONFIG_FALLBACK_TO_EMPTY_NAMESPACE = "struts.actionConfig.fallbackToEmptyNamespace"; /** The {@link com.opensymphony.xwork2.LocaleProviderFactory} implementation class */ public static final String STRUTS_LOCALE_PROVIDER_FACTORY = "struts.localeProviderFactory"; diff --git a/core/src/main/java/org/apache/struts2/config/entities/ConstantConfig.java b/core/src/main/java/org/apache/struts2/config/entities/ConstantConfig.java index b7d4626095..3f7484f16c 100644 --- a/core/src/main/java/org/apache/struts2/config/entities/ConstantConfig.java +++ b/core/src/main/java/org/apache/struts2/config/entities/ConstantConfig.java @@ -90,7 +90,7 @@ public class ConstantConfig { private Boolean freemarkerWrapperAltMap; private BeanConfig xworkConverter; private Boolean mapperAlwaysSelectFullNamespace; - private Boolean proxyDisableEmptyNamespaceFallback; + private Boolean actionConfigFallbackToEmptyNamespace; private BeanConfig localeProviderFactory; private String mapperIdParameterName; private Boolean ognlAllowStaticFieldAccess; @@ -226,7 +226,7 @@ public Map getAllAsStringsMap() { map.put(StrutsConstants.STRUTS_FREEMARKER_WRAPPER_ALT_MAP, Objects.toString(freemarkerWrapperAltMap, null)); map.put(StrutsConstants.STRUTS_XWORKCONVERTER, beanConfToString(xworkConverter)); map.put(StrutsConstants.STRUTS_ALWAYS_SELECT_FULL_NAMESPACE, Objects.toString(mapperAlwaysSelectFullNamespace, null)); - map.put(StrutsConstants.STRUTS_DISABLE_EMPTY_NAMESPACE_FALLBACK, Objects.toString(proxyDisableEmptyNamespaceFallback, null)); + map.put(StrutsConstants.STRUTS_ACTION_CONFIG_FALLBACK_TO_EMPTY_NAMESPACE, Objects.toString(actionConfigFallbackToEmptyNamespace, null)); map.put(StrutsConstants.STRUTS_LOCALE_PROVIDER_FACTORY, beanConfToString(localeProviderFactory)); map.put(StrutsConstants.STRUTS_ID_PARAMETER_NAME, mapperIdParameterName); map.put(StrutsConstants.STRUTS_ALLOW_STATIC_FIELD_ACCESS, Objects.toString(ognlAllowStaticFieldAccess, null)); @@ -814,12 +814,12 @@ public void setMapperAlwaysSelectFullNamespace(Boolean mapperAlwaysSelectFullNam this.mapperAlwaysSelectFullNamespace = mapperAlwaysSelectFullNamespace; } - public Boolean getProxyDisableEmptyNamespaceFallback() { - return proxyDisableEmptyNamespaceFallback; + public Boolean getActionConfigFallbackToEmptyNamespace() { + return actionConfigFallbackToEmptyNamespace; } - public void setProxyDisableEmptyNamespaceFallback(Boolean proxyDisableEmptyNamespaceFallback) { - this.proxyDisableEmptyNamespaceFallback = proxyDisableEmptyNamespaceFallback; + public void setActionConfigFallbackToEmptyNamespace(Boolean actionConfigFallbackToEmptyNamespace) { + this.actionConfigFallbackToEmptyNamespace = actionConfigFallbackToEmptyNamespace; } public BeanConfig getLocaleProviderFactory() { diff --git a/core/src/test/java/com/opensymphony/xwork2/config/ConfigurationTest.java b/core/src/test/java/com/opensymphony/xwork2/config/ConfigurationTest.java index 8b9b36618d..520f8c2409 100644 --- a/core/src/test/java/com/opensymphony/xwork2/config/ConfigurationTest.java +++ b/core/src/test/java/com/opensymphony/xwork2/config/ConfigurationTest.java @@ -240,8 +240,8 @@ public void testMultipleContainerProviders() { mockContainerProvider.verify(); } - public void testGetActionConfigFallbackToEmptyNamespaceWhenNamespaceDontMatchAndEmptyNamespaceFallbackIsNotDisabled() { - // struts.disableEmptyNamespaceFallback default to null, so it's not disabled + public void testGetActionConfigFallbackToEmptyNamespaceWhenNamespaceDontMatchAndEmptyNamespaceFallbackIsEnabled() { + // struts.actionConfig.fallbackToEmptyNamespace default to true, so it is enabled RuntimeConfiguration configuration = configurationManager.getConfiguration().getRuntimeConfiguration(); // check namespace that doesn't match fallback to empty namespace @@ -259,8 +259,8 @@ public void testGetActionConfigFallbackToEmptyNamespaceWhenNamespaceDontMatchAnd } public void testGetActionConfigReturnNullWhenNamespaceDontMatchAndEmptyNamespaceFallbackIsDisabled() { - // set the struts.disableEmptyNamespaceFallback to true and reload the configuration - setStrutsConstant(StrutsConstants.STRUTS_DISABLE_EMPTY_NAMESPACE_FALLBACK, "true"); + // set the struts.actionConfig.fallbackToEmptyNamespace to false and reload the configuration + setStrutsConstant(StrutsConstants.STRUTS_ACTION_CONFIG_FALLBACK_TO_EMPTY_NAMESPACE, "false"); RuntimeConfiguration configuration = configurationManager.getConfiguration().getRuntimeConfiguration(); // check namespace that doesn't match NOT fallback to empty namespace and return null From 1d51d00ecbf6e6573914bc04a3ed2870179b9640 Mon Sep 17 00:00:00 2001 From: Jeffery Xie Date: Thu, 11 Apr 2024 14:57:57 +1000 Subject: [PATCH 3/3] WW-5408 add struts.actionConfig.fallbackToEmptyNamespace as true in default.properties --- .../xwork2/config/impl/DefaultConfiguration.java | 6 +++++- .../main/resources/org/apache/struts2/default.properties | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java b/core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java index b0d7be13eb..7c725e15b0 100644 --- a/core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java +++ b/core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java @@ -590,13 +590,17 @@ public ActionConfig getActionConfig(String namespace, String name) { } // fail over to empty namespace - if (config == null && StringUtils.isNotBlank(namespace) && ("/".equals(namespace) || fallbackToEmptyNamespace)) { + if (config == null && shouldFallbackToEmptyNamespace(namespace)) { config = findActionConfigInNamespace("", name); } return config; } + private boolean shouldFallbackToEmptyNamespace(String namespace) { + return StringUtils.isNotBlank(namespace) && ("/".equals(namespace) || fallbackToEmptyNamespace); + } + private ActionConfig findActionConfigInNamespace(String namespace, String name) { ActionConfig config = null; if (namespace == null) { diff --git a/core/src/main/resources/org/apache/struts2/default.properties b/core/src/main/resources/org/apache/struts2/default.properties index 96c5459fe6..8b7226a89b 100644 --- a/core/src/main/resources/org/apache/struts2/default.properties +++ b/core/src/main/resources/org/apache/struts2/default.properties @@ -215,6 +215,9 @@ struts.xslt.nocache=false ### Whether to always select the namespace to be everything before the last slash or not struts.mapper.alwaysSelectFullNamespace=false +### Whether to fallback to empty namespace when request namespace does not match any in configuration +struts.actionConfig.fallbackToEmptyNamespace=true + ### Whether to allow static field access in OGNL expressions or not struts.ognl.allowStaticFieldAccess=true