diff --git a/core/src/main/java/org/apache/struts2/StrutsConstants.java b/core/src/main/java/org/apache/struts2/StrutsConstants.java
index 44efda5ba..651e02559 100644
--- a/core/src/main/java/org/apache/struts2/StrutsConstants.java
+++ b/core/src/main/java/org/apache/struts2/StrutsConstants.java
@@ -145,4 +145,6 @@ public final class StrutsConstants {
/** The name of the xwork converter implementation */
public static final String STRUTS_XWORKCONVERTER = "struts.xworkConverter";
+
+ public static final String STRUTS_ALWAYS_SELECT_FULL_NAMESPACE = "struts.mapper.alwaysSelectFullNamespace";
}
diff --git a/core/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper.java b/core/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper.java
index df25d59a1..f334c87d4 100644
--- a/core/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper.java
+++ b/core/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper.java
@@ -173,6 +173,8 @@ public class DefaultActionMapper implements ActionMapper {
private boolean allowDynamicMethodCalls = true;
private boolean allowSlashesInActionNames = false;
+
+ private boolean alwaysSelectFullNamespace = false;
private PrefixTrie prefixTrie = null;
@@ -243,6 +245,11 @@ public class DefaultActionMapper implements ActionMapper {
public void setSlashesInActionNames(String allow) {
allowSlashesInActionNames = "true".equals(allow);
}
+
+ @Inject(StrutsConstants.STRUTS_ALWAYS_SELECT_FULL_NAMESPACE)
+ public void setAlwaysSelectFullNamespace(String val) {
+ this.alwaysSelectFullNamespace = "true".equals(val);
+ }
@Inject
public void setContainer(Container container) {
@@ -264,7 +271,7 @@ public class DefaultActionMapper implements ActionMapper {
return null;
}
- parseNameAndNamespace(uri, mapping, configManager.getConfiguration());
+ parseNameAndNamespace(uri, mapping, configManager);
handleSpecialParameters(request, mapping);
@@ -330,7 +337,7 @@ public class DefaultActionMapper implements ActionMapper {
* The action mapping to populate
*/
void parseNameAndNamespace(String uri, ActionMapping mapping,
- Configuration config) {
+ ConfigurationManager configManager) {
String namespace, name;
int lastSlash = uri.lastIndexOf("/");
if (lastSlash == -1) {
@@ -342,7 +349,13 @@ public class DefaultActionMapper implements ActionMapper {
// namespace anyway if not found in root namespace.
namespace = "/";
name = uri.substring(lastSlash + 1);
+ } else if (alwaysSelectFullNamespace) {
+ // Simply select the namespace as everything before the last slash
+ namespace = uri.substring(0, lastSlash);
+ name = uri.substring(lastSlash + 1);
} else {
+ // Try to find the namespace in those defined, defaulting to ""
+ Configuration config = configManager.getConfiguration();
String prefix = uri.substring(0, lastSlash);
namespace = "";
// Find the longest matching namespace, defaulting to the default
diff --git a/core/src/main/resources/org/apache/struts2/default.properties b/core/src/main/resources/org/apache/struts2/default.properties
index 2c0420fc0..694e71b25 100644
--- a/core/src/main/resources/org/apache/struts2/default.properties
+++ b/core/src/main/resources/org/apache/struts2/default.properties
@@ -161,4 +161,7 @@ struts.templateEngines=ftl,jsp,vm
### A list of tag libraries available
struts.tagLibraries=s
+### Whether to always select the namespace to be everything before the last slash or not
+struts.mapper.alwaysSelectFullNamespace=false
+
### END SNIPPET: complete_file
diff --git a/core/src/test/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapperTest.java b/core/src/test/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapperTest.java
index bcdaac391..0c3f58112 100644
--- a/core/src/test/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapperTest.java
+++ b/core/src/test/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapperTest.java
@@ -154,6 +154,22 @@ public class DefaultActionMapperTest extends StrutsTestCase {
assertEquals("actionName", mapping.getName());
assertNull(mapping.getMethod());
}
+
+ public void testGetMappingWithUnknownNamespaceButFullNamespaceSelect() throws Exception {
+ setUp();
+ req.setupGetRequestURI("/bo/foo/actionName.action");
+ req.setupGetServletPath("/bo/foo/actionName.action");
+ req.setupGetAttribute(null);
+ req.addExpectedGetAttributeName("javax.servlet.include.servlet_path");
+
+ DefaultActionMapper mapper = new DefaultActionMapper();
+ mapper.setAlwaysSelectFullNamespace("true");
+ ActionMapping mapping = mapper.getMapping(req, configManager);
+
+ assertEquals("/bo/foo", mapping.getNamespace());
+ assertEquals("actionName", mapping.getName());
+ assertNull(mapping.getMethod());
+ }
public void testGetUri() throws Exception {
req.setupGetParameterMap(new HashMap());
@@ -204,7 +220,7 @@ public class DefaultActionMapperTest extends StrutsTestCase {
ActionMapping actionMapping = new ActionMapping();
DefaultActionMapper defaultActionMapper = new DefaultActionMapper();
- defaultActionMapper.parseNameAndNamespace("someAction", actionMapping, config);
+ defaultActionMapper.parseNameAndNamespace("someAction", actionMapping, configManager);
assertEquals(actionMapping.getName(), "someAction");
assertEquals(actionMapping.getNamespace(), "");
@@ -214,7 +230,7 @@ public class DefaultActionMapperTest extends StrutsTestCase {
ActionMapping actionMapping = new ActionMapping();
DefaultActionMapper defaultActionMapper = new DefaultActionMapper();
- defaultActionMapper.parseNameAndNamespace("/someAction", actionMapping, config);
+ defaultActionMapper.parseNameAndNamespace("/someAction", actionMapping, configManager);
assertEquals(actionMapping.getName(), "someAction");
assertEquals(actionMapping.getNamespace(), "/");
@@ -224,7 +240,7 @@ public class DefaultActionMapperTest extends StrutsTestCase {
ActionMapping actionMapping = new ActionMapping();
DefaultActionMapper defaultActionMapper = new DefaultActionMapper();
- defaultActionMapper.parseNameAndNamespace("/my/someAction", actionMapping, config);
+ defaultActionMapper.parseNameAndNamespace("/my/someAction", actionMapping, configManager);
assertEquals(actionMapping.getName(), "someAction");
assertEquals(actionMapping.getNamespace(), "/my");
@@ -235,7 +251,7 @@ public class DefaultActionMapperTest extends StrutsTestCase {
DefaultActionMapper defaultActionMapper = new DefaultActionMapper();
defaultActionMapper.setSlashesInActionNames("false");
- defaultActionMapper.parseNameAndNamespace("/foo/someAction", actionMapping, config);
+ defaultActionMapper.parseNameAndNamespace("/foo/someAction", actionMapping, configManager);
assertEquals(actionMapping.getName(), "someAction");
assertEquals(actionMapping.getNamespace(), "");
@@ -246,7 +262,7 @@ public class DefaultActionMapperTest extends StrutsTestCase {
DefaultActionMapper defaultActionMapper = new DefaultActionMapper();
defaultActionMapper.setSlashesInActionNames("true");
- defaultActionMapper.parseNameAndNamespace("/foo/someAction", actionMapping, config);
+ defaultActionMapper.parseNameAndNamespace("/foo/someAction", actionMapping, configManager);
assertEquals(actionMapping.getName(), "foo/someAction");
assertEquals(actionMapping.getNamespace(), "");
diff --git a/plugins/codebehind/src/main/resources/struts-plugin.xml b/plugins/codebehind/src/main/resources/struts-plugin.xml
index 1b8a7a72b..21afbe86a 100644
--- a/plugins/codebehind/src/main/resources/struts-plugin.xml
+++ b/plugins/codebehind/src/main/resources/struts-plugin.xml
@@ -9,6 +9,7 @@
+