This is an automated email from the ASF dual-hosted git repository.

kusal pushed a commit to branch WW-5468-modeldriven-strutsparameter-fix
in repository https://gitbox.apache.org/repos/asf/struts.git

commit 7cdcd84b838eaea5a3f10af5ea64e6856dc3c27d
Author: Kusal Kithul-Godage <g...@kusal.io>
AuthorDate: Mon Oct 14 18:59:11 2024 +1100

    Merge pull request #1072 from apache/fix/WW-5468-modeldriven-2
    
    WW-5468 Exempt ModelDriven Actions from @StrutsParameter requirement
---
 .../showcase/modelDriven/ModelDrivenAction.java    |   2 +-
 .../main/java/org/apache/struts2/ModelDriven.java  |   6 +
 .../parameter/ParametersInterceptor.java           |  45 ++-
 .../com/opensymphony/xwork2/ModelDrivenAction.java |   3 +-
 .../xwork2/ModelDrivenAnnotationAction.java        |   3 +-
 .../interceptor/ModelDrivenInterceptorTest.java    |   2 +-
 .../xwork2/test/ModelDrivenAction2.java            |   4 +-
 .../xwork2/test/ModelDrivenAnnotationAction2.java  |   4 +-
 .../xwork2/test/subtest/NullModelDrivenAction.java |   3 +-
 .../validator/VisitorValidatorModelAction.java     |   5 +-
 .../parameter/StrutsParameterAnnotationTest.java   |  36 +-
 .../apache/struts2/result/StreamResultTest.java    |   6 +-
 .../beanvalidation/actions/ModelDrivenAction.java  |   2 -
 .../actions/ValidateGroupAction.java               |   2 -
 .../apache/struts2/junit/StrutsRestTestCase.java   |   3 +-
 .../struts2/rest/RestActionInvocationTest.java     | 400 ++++++++++-----------
 .../com/opensymphony/xwork2/ModelDrivenAction.java |   3 +-
 17 files changed, 281 insertions(+), 248 deletions(-)

diff --git 
a/apps/showcase/src/main/java/org/apache/struts2/showcase/modelDriven/ModelDrivenAction.java
 
b/apps/showcase/src/main/java/org/apache/struts2/showcase/modelDriven/ModelDrivenAction.java
index 60692b0e6..0fae6c481 100644
--- 
a/apps/showcase/src/main/java/org/apache/struts2/showcase/modelDriven/ModelDrivenAction.java
+++ 
b/apps/showcase/src/main/java/org/apache/struts2/showcase/modelDriven/ModelDrivenAction.java
@@ -42,7 +42,7 @@ public class ModelDrivenAction extends ActionSupport 
implements ModelDriven {
        }
 
        @Override
-       public Object getModel() {
+       public Gangster getModel() {
                return new Gangster();
        }
 }
diff --git a/core/src/main/java/org/apache/struts2/ModelDriven.java 
b/core/src/main/java/org/apache/struts2/ModelDriven.java
index 0704109f1..993a6f5eb 100644
--- a/core/src/main/java/org/apache/struts2/ModelDriven.java
+++ b/core/src/main/java/org/apache/struts2/ModelDriven.java
@@ -18,6 +18,8 @@
  */
 package org.apache.struts2;
 
+import org.apache.struts2.interceptor.parameter.StrutsParameter;
+
 /**
  * ModelDriven Actions provide a model object to be pushed onto the ValueStack
  * in addition to the Action itself, allowing a FormBean type approach like 
Struts.
@@ -28,9 +30,13 @@ public interface ModelDriven<T> {
 
     /**
      * Gets the model to be pushed onto the ValueStack instead of the Action 
itself.
+     * <p>
+     * Please be aware that all setters and getters of every depth on the 
object returned by this method are available
+     * for user parameter injection!
      *
      * @return the model
      */
+    @StrutsParameter(depth = Integer.MAX_VALUE)
     T getModel();
 
 }
diff --git 
a/core/src/main/java/org/apache/struts2/interceptor/parameter/ParametersInterceptor.java
 
b/core/src/main/java/org/apache/struts2/interceptor/parameter/ParametersInterceptor.java
index 239bc6d6c..9f6ff8f53 100644
--- 
a/core/src/main/java/org/apache/struts2/interceptor/parameter/ParametersInterceptor.java
+++ 
b/core/src/main/java/org/apache/struts2/interceptor/parameter/ParametersInterceptor.java
@@ -35,6 +35,7 @@ import org.apache.commons.lang3.BooleanUtils;
 import org.apache.commons.lang3.ClassUtils;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
+import org.apache.struts2.ModelDriven;
 import org.apache.struts2.StrutsConstants;
 import org.apache.struts2.action.NoParameters;
 import org.apache.struts2.action.ParameterNameAware;
@@ -348,7 +349,15 @@ public class ParametersInterceptor extends 
MethodFilterInterceptor {
         }
 
         long paramDepth = name.codePoints().mapToObj(c -> (char) 
c).filter(NESTING_CHARS::contains).count();
+
+        if (action instanceof ModelDriven<?> && 
!ActionContext.getContext().getValueStack().peek().equals(action)) {
+            LOG.debug("Model driven Action detected, exempting from 
@StrutsParameter annotation requirement and OGNL allowlisting model type");
+            // (Exempted by annotation on 
com.opensymphony.xwork2.ModelDriven#getModel)
+            return hasValidAnnotatedMember("model", action, paramDepth + 1);
+        }
+
         if (requireAnnotationsTransitionMode && paramDepth == 0) {
+            LOG.debug("Annotation transition mode enabled, exempting 
non-nested parameter [{}] from @StrutsParameter annotation requirement", name);
             return true;
         }
 
@@ -365,6 +374,8 @@ public class ParametersInterceptor extends 
MethodFilterInterceptor {
      * save computation by checking this last.
      */
     protected boolean hasValidAnnotatedMember(String rootProperty, Object 
action, long paramDepth) {
+        LOG.debug("Checking Action [{}] for a matching, correctly annotated 
member for property [{}]",
+                action.getClass().getSimpleName(), rootProperty);
         BeanInfo beanInfo = getBeanInfo(action);
         if (beanInfo == null) {
             return hasValidAnnotatedField(action, rootProperty, paramDepth);
@@ -399,7 +410,7 @@ public class ParametersInterceptor extends 
MethodFilterInterceptor {
         }
         if (getPermittedInjectionDepth(relevantMethod) < paramDepth) {
             String logMessage = format(
-                    "Parameter injection for method [%s] on action [%s] 
rejected. Ensure it is annotated with @StrutsParameter with an appropriate 
'depth'.",
+                    "Parameter injection for method [%s] on Action [%s] 
rejected. Ensure it is annotated with @StrutsParameter with an appropriate 
'depth'.",
                     relevantMethod.getName(),
                     relevantMethod.getDeclaringClass().getName());
             if (devMode) {
@@ -409,8 +420,10 @@ public class ParametersInterceptor extends 
MethodFilterInterceptor {
             }
             return false;
         }
+        LOG.debug("Success: Matching annotated method [{}] found for property 
[{}] of depth [{}] on Action [{}]",
+                relevantMethod.getName(), propDesc.getName(), paramDepth, 
action.getClass().getSimpleName());
         if (paramDepth >= 1) {
-            allowlistClass(relevantMethod.getReturnType());
+            allowlistClass(propDesc.getPropertyType());
         }
         if (paramDepth >= 2) {
             allowlistReturnTypeIfParameterized(relevantMethod);
@@ -447,19 +460,23 @@ public class ParametersInterceptor extends 
MethodFilterInterceptor {
     }
 
     protected boolean hasValidAnnotatedField(Object action, String fieldName, 
long paramDepth) {
+        LOG.debug("No matching annotated method found for property [{}] of 
depth [{}] on Action [{}], now also checking for public field",
+                fieldName, paramDepth, action.getClass().getSimpleName());
         Field field;
         try {
             field = action.getClass().getDeclaredField(fieldName);
         } catch (NoSuchFieldException e) {
+            LOG.debug("Matching field for property [{}] not found on Action 
[{}]", fieldName, action.getClass().getSimpleName());
             return false;
         }
         if (!Modifier.isPublic(field.getModifiers())) {
+            LOG.debug("Matching field [{}] is not public on Action [{}]", 
field.getName(), action.getClass().getSimpleName());
             return false;
         }
         if (getPermittedInjectionDepth(field) < paramDepth) {
             String logMessage = format(
-                    "Parameter injection for field [%s] on action [%s] 
rejected. Ensure it is annotated with @StrutsParameter with an appropriate 
'depth'.",
-                    fieldName,
+                    "Parameter injection for field [%s] on Action [%s] 
rejected. Ensure it is annotated with @StrutsParameter with an appropriate 
'depth'.",
+                    field.getName(),
                     action.getClass().getName());
             if (devMode) {
                 notifyDeveloperOfError(LOG, action, logMessage);
@@ -468,6 +485,8 @@ public class ParametersInterceptor extends 
MethodFilterInterceptor {
             }
             return false;
         }
+        LOG.debug("Success: Matching annotated public field [{}] found for 
property of depth [{}] on Action [{}]",
+                field.getName(), paramDepth, 
action.getClass().getSimpleName());
         if (paramDepth >= 1) {
             allowlistClass(field.getType());
         }
@@ -629,7 +648,7 @@ public class ParametersInterceptor extends 
MethodFilterInterceptor {
         if (!result.isAccepted()) {
             if (devMode) {
                 LOG.warn("Parameter [{}] didn't match accepted pattern [{}]! 
See Accepted / Excluded patterns at\n" +
-                                
"https://struts.apache.org/security/#accepted--excluded-patterns";,
+                         
"https://struts.apache.org/security/#accepted--excluded-patterns";,
                         paramName, result.getAcceptedPattern());
             } else {
                 LOG.debug("Parameter [{}] didn't match accepted pattern 
[{}]!", paramName, result.getAcceptedPattern());
@@ -644,8 +663,8 @@ public class ParametersInterceptor extends 
MethodFilterInterceptor {
         if (result.isExcluded()) {
             if (devMode) {
                 LOG.warn("Parameter [{}] matches excluded pattern [{}]! See 
Accepted / Excluded patterns at\n" +
-                        
"https://struts.apache.org/security/#accepted--excluded-patterns";,
-                    paramName, result.getExcludedPattern());
+                         
"https://struts.apache.org/security/#accepted--excluded-patterns";,
+                        paramName, result.getExcludedPattern());
             } else {
                 LOG.debug("Parameter [{}] matches excluded pattern [{}]!", 
paramName, result.getExcludedPattern());
             }
@@ -663,8 +682,8 @@ public class ParametersInterceptor extends 
MethodFilterInterceptor {
             if (excludedValuePattern.matcher(value).matches()) {
                 if (devMode) {
                     LOG.warn("Parameter value [{}] matches excluded pattern 
[{}]! See Accepting/Excluding parameter values at\n" +
-                            
"https://struts.apache.org/core-developers/parameters-interceptor#excluding-parameter-values";,
-                        value, excludedValuePatterns);
+                             
"https://struts.apache.org/core-developers/parameters-interceptor#excluding-parameter-values";,
+                            value, excludedValuePatterns);
                 } else {
                     LOG.debug("Parameter value [{}] matches excluded pattern 
[{}]", value, excludedValuePattern);
                 }
@@ -686,8 +705,8 @@ public class ParametersInterceptor extends 
MethodFilterInterceptor {
         }
         if (devMode) {
             LOG.warn("Parameter value [{}] didn't match accepted pattern [{}]! 
See Accepting/Excluding parameter values at\n" +
-                    
"https://struts.apache.org/core-developers/parameters-interceptor#excluding-parameter-values";,
-                value, acceptedValuePatterns);
+                     
"https://struts.apache.org/core-developers/parameters-interceptor#excluding-parameter-values";,
+                    value, acceptedValuePatterns);
         } else {
             LOG.debug("Parameter value [{}] was not accepted!", value);
         }
@@ -757,7 +776,7 @@ public class ParametersInterceptor extends 
MethodFilterInterceptor {
             LOG.debug("Sets accepted value patterns to [{}], note this may 
impact the safety of your application!", patterns);
         } else {
             LOG.warn("Replacing accepted patterns [{}] with [{}], be aware 
that this may impact safety of your application!",
-                acceptedValuePatterns, patterns);
+                    acceptedValuePatterns, patterns);
         }
         acceptedValuePatterns = new HashSet<>(patterns.size());
         try {
@@ -782,7 +801,7 @@ public class ParametersInterceptor extends 
MethodFilterInterceptor {
             LOG.debug("Setting excluded value patterns to [{}]", patterns);
         } else {
             LOG.warn("Replacing excluded value patterns [{}] with [{}], be 
aware that this may impact safety of your application!",
-                excludedValuePatterns, patterns);
+                    excludedValuePatterns, patterns);
         }
         excludedValuePatterns = new HashSet<>(patterns.size());
         try {
diff --git a/core/src/test/java/com/opensymphony/xwork2/ModelDrivenAction.java 
b/core/src/test/java/com/opensymphony/xwork2/ModelDrivenAction.java
index 6ffcad2ff..e300d036b 100644
--- a/core/src/test/java/com/opensymphony/xwork2/ModelDrivenAction.java
+++ b/core/src/test/java/com/opensymphony/xwork2/ModelDrivenAction.java
@@ -44,9 +44,8 @@ public class ModelDrivenAction extends ActionSupport 
implements ModelDriven {
     /**
      * @return the model to be pushed onto the ValueStack after the Action 
itself
      */
-    @StrutsParameter(depth = 2)
     @Override
-    public Object getModel() {
+    public TestBean getModel() {
         return model;
     }
 }
diff --git 
a/core/src/test/java/com/opensymphony/xwork2/ModelDrivenAnnotationAction.java 
b/core/src/test/java/com/opensymphony/xwork2/ModelDrivenAnnotationAction.java
index 5549b60b1..f05641732 100644
--- 
a/core/src/test/java/com/opensymphony/xwork2/ModelDrivenAnnotationAction.java
+++ 
b/core/src/test/java/com/opensymphony/xwork2/ModelDrivenAnnotationAction.java
@@ -44,9 +44,8 @@ public class ModelDrivenAnnotationAction extends 
ActionSupport implements ModelD
     /**
      * @return the model to be pushed onto the ValueStack after the Action 
itself
      */
-    @StrutsParameter(depth = 2)
     @Override
-    public Object getModel() {
+    public AnnotatedTestBean getModel() {
         return model;
     }
 }
diff --git 
a/core/src/test/java/com/opensymphony/xwork2/interceptor/ModelDrivenInterceptorTest.java
 
b/core/src/test/java/com/opensymphony/xwork2/interceptor/ModelDrivenInterceptorTest.java
index 65b21c86d..f6513f5f2 100644
--- 
a/core/src/test/java/com/opensymphony/xwork2/interceptor/ModelDrivenInterceptorTest.java
+++ 
b/core/src/test/java/com/opensymphony/xwork2/interceptor/ModelDrivenInterceptorTest.java
@@ -178,7 +178,7 @@ public class ModelDrivenInterceptorTest extends 
XWorkTestCase {
     }
 
 
-    public class ModelDrivenAction extends ActionSupport implements 
ModelDriven {
+    public class ModelDrivenAction extends ActionSupport implements 
ModelDriven<Object> {
 
         @Override
         public Object getModel() {
diff --git 
a/core/src/test/java/com/opensymphony/xwork2/test/ModelDrivenAction2.java 
b/core/src/test/java/com/opensymphony/xwork2/test/ModelDrivenAction2.java
index 0c445860b..5e29e6899 100644
--- a/core/src/test/java/com/opensymphony/xwork2/test/ModelDrivenAction2.java
+++ b/core/src/test/java/com/opensymphony/xwork2/test/ModelDrivenAction2.java
@@ -19,7 +19,6 @@
 package com.opensymphony.xwork2.test;
 
 import com.opensymphony.xwork2.ModelDrivenAction;
-import org.apache.struts2.interceptor.parameter.StrutsParameter;
 
 
 /**
@@ -35,9 +34,8 @@ public class ModelDrivenAction2 extends ModelDrivenAction {
     /**
      * @return the model to be pushed onto the ValueStack after the Action 
itself
      */
-    @StrutsParameter(depth = 3)
     @Override
-    public Object getModel() {
+    public TestBean2 getModel() {
         return model;
     }
 }
diff --git 
a/core/src/test/java/com/opensymphony/xwork2/test/ModelDrivenAnnotationAction2.java
 
b/core/src/test/java/com/opensymphony/xwork2/test/ModelDrivenAnnotationAction2.java
index 7c26dcfab..b2fcdf542 100644
--- 
a/core/src/test/java/com/opensymphony/xwork2/test/ModelDrivenAnnotationAction2.java
+++ 
b/core/src/test/java/com/opensymphony/xwork2/test/ModelDrivenAnnotationAction2.java
@@ -19,7 +19,6 @@
 package com.opensymphony.xwork2.test;
 
 import com.opensymphony.xwork2.ModelDrivenAnnotationAction;
-import org.apache.struts2.interceptor.parameter.StrutsParameter;
 
 
 /**
@@ -36,9 +35,8 @@ public class ModelDrivenAnnotationAction2 extends 
ModelDrivenAnnotationAction {
     /**
      * @return the model to be pushed onto the ValueStack after the Action 
itself
      */
-    @StrutsParameter(depth = 3)
     @Override
-    public Object getModel() {
+    public AnnotationTestBean2 getModel() {
         return model;
     }
 }
diff --git 
a/core/src/test/java/com/opensymphony/xwork2/test/subtest/NullModelDrivenAction.java
 
b/core/src/test/java/com/opensymphony/xwork2/test/subtest/NullModelDrivenAction.java
index be0916d9d..3551a4643 100644
--- 
a/core/src/test/java/com/opensymphony/xwork2/test/subtest/NullModelDrivenAction.java
+++ 
b/core/src/test/java/com/opensymphony/xwork2/test/subtest/NullModelDrivenAction.java
@@ -19,6 +19,7 @@
 package com.opensymphony.xwork2.test.subtest;
 
 import com.opensymphony.xwork2.ModelDrivenAction;
+import com.opensymphony.xwork2.TestBean;
 
 /**
  * Extends ModelDrivenAction to return a null model.
@@ -31,7 +32,7 @@ public class NullModelDrivenAction extends ModelDrivenAction {
      * @return the model to be pushed onto the ValueStack instead of the 
Action itself
      */
     @Override
-    public Object getModel() {
+    public TestBean getModel() {
         return null;
     }
 }
diff --git 
a/core/src/test/java/com/opensymphony/xwork2/validator/VisitorValidatorModelAction.java
 
b/core/src/test/java/com/opensymphony/xwork2/validator/VisitorValidatorModelAction.java
index 9f5baeee0..9ec226f98 100644
--- 
a/core/src/test/java/com/opensymphony/xwork2/validator/VisitorValidatorModelAction.java
+++ 
b/core/src/test/java/com/opensymphony/xwork2/validator/VisitorValidatorModelAction.java
@@ -19,7 +19,7 @@
 package com.opensymphony.xwork2.validator;
 
 import com.opensymphony.xwork2.ModelDriven;
-import org.apache.struts2.interceptor.parameter.StrutsParameter;
+import com.opensymphony.xwork2.TestBean;
 
 
 /**
@@ -33,9 +33,8 @@ public class VisitorValidatorModelAction extends 
VisitorValidatorTestAction impl
     /**
      * @return the model to be pushed onto the ValueStack instead of the 
Action itself
      */
-    @StrutsParameter(depth = 2)
     @Override
-    public Object getModel() {
+    public TestBean getModel() {
         return getBean();
     }
 }
diff --git 
a/core/src/test/java/org/apache/struts2/interceptor/parameter/StrutsParameterAnnotationTest.java
 
b/core/src/test/java/org/apache/struts2/interceptor/parameter/StrutsParameterAnnotationTest.java
index 53fa14717..dfcecddcb 100644
--- 
a/core/src/test/java/org/apache/struts2/interceptor/parameter/StrutsParameterAnnotationTest.java
+++ 
b/core/src/test/java/org/apache/struts2/interceptor/parameter/StrutsParameterAnnotationTest.java
@@ -18,8 +18,12 @@
  */
 package org.apache.struts2.interceptor.parameter;
 
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.ModelDriven;
+import com.opensymphony.xwork2.StubValueStack;
 import com.opensymphony.xwork2.security.AcceptedPatternsChecker;
 import com.opensymphony.xwork2.security.NotExcludedAcceptedPatternsChecker;
+import com.opensymphony.xwork2.util.ValueStack;
 import org.apache.commons.lang3.ClassUtils;
 import org.apache.struts2.dispatcher.HttpParameters;
 import org.apache.struts2.dispatcher.Parameter;
@@ -63,6 +67,7 @@ public class StrutsParameterAnnotationTest {
     @After
     public void tearDown() throws Exception {
         threadAllowlist.clearAllowlist();
+        ActionContext.clear();
     }
 
     private void testParameter(Object action, String paramName, boolean 
shouldContain) {
@@ -80,7 +85,7 @@ public class StrutsParameterAnnotationTest {
         }
     }
 
-    private Set<Class<?>> getParentClasses(Class<?> ...clazzes) {
+    private Set<Class<?>> getParentClasses(Class<?>... clazzes) {
         Set<Class<?>> set = new HashSet<>();
         for (Class<?> clazz : clazzes) {
             set.add(clazz);
@@ -258,8 +263,21 @@ public class StrutsParameterAnnotationTest {
         testParameter(new MethodAction(), "publicStrNotAnnotated", true);
     }
 
+    @Test
+    public void publicModelPojo() {
+        ModelAction action = new ModelAction();
+
+        // Emulate ModelDrivenInterceptor running previously
+        ValueStack valueStack = new StubValueStack();
+        valueStack.push(action.getModel());
+        ActionContext.of().withValueStack(valueStack).bind();
+
+        testParameter(action, "name", true);
+        testParameter(action, "name.nested", true);
+        
assertThat(threadAllowlist.getAllowlist()).containsExactlyInAnyOrderElementsOf(getParentClasses(Object.class,
 Pojo.class));
+    }
 
-    class FieldAction {
+    static class FieldAction {
         @StrutsParameter
         private String privateStr;
 
@@ -275,7 +293,7 @@ public class StrutsParameterAnnotationTest {
         public Pojo publicPojoDepthZero;
 
         @StrutsParameter(depth = 1)
-        public Pojo publicPojoDepthOne ;
+        public Pojo publicPojoDepthOne;
 
         @StrutsParameter(depth = 2)
         public Pojo publicPojoDepthTwo;
@@ -290,7 +308,7 @@ public class StrutsParameterAnnotationTest {
         public Map<String, Pojo> publicPojoMapDepthTwo;
     }
 
-    class MethodAction {
+    static class MethodAction {
 
         @StrutsParameter
         private void setPrivateStr(String str) {
@@ -343,6 +361,14 @@ public class StrutsParameterAnnotationTest {
         }
     }
 
-    class Pojo {
+    static class ModelAction implements ModelDriven<Pojo> {
+
+        @Override
+        public Pojo getModel() {
+            return new Pojo();
+        }
+    }
+
+    static class Pojo {
     }
 }
diff --git a/core/src/test/java/org/apache/struts2/result/StreamResultTest.java 
b/core/src/test/java/org/apache/struts2/result/StreamResultTest.java
index 5661db5d3..a02781812 100644
--- a/core/src/test/java/org/apache/struts2/result/StreamResultTest.java
+++ b/core/src/test/java/org/apache/struts2/result/StreamResultTest.java
@@ -37,7 +37,6 @@ import static 
com.opensymphony.xwork2.security.DefaultNotExcludedAcceptedPattern
 
 /**
  * Unit test for {@link StreamResult}.
- *
  */
 public class StreamResultTest extends StrutsInternalTestCase {
 
@@ -126,12 +125,12 @@ public class StreamResultTest extends 
StrutsInternalTestCase {
 
         result.doExecute("helloworld", mai);
 
-        //check that that headers are not set by default        
+        //check that that headers are not set by default
         assertNull(response.getHeader("Pragma"));
         assertNull(response.getHeader("Cache-Control"));
     }
 
-     public void testAllowCacheFalse() throws Exception {
+    public void testAllowCacheFalse() throws Exception {
         result.setInputName("streamForImage");
         result.setAllowCaching(false);
         result.doExecute("helloworld", mai);
@@ -266,7 +265,6 @@ public class StreamResultTest extends 
StrutsInternalTestCase {
     }
 
 
-
     protected void tearDown() throws Exception {
         super.tearDown();
         response = null;
diff --git 
a/plugins/bean-validation/src/test/java/org/apache/struts/beanvalidation/actions/ModelDrivenAction.java
 
b/plugins/bean-validation/src/test/java/org/apache/struts/beanvalidation/actions/ModelDrivenAction.java
index 9b32fa24b..3964ed397 100644
--- 
a/plugins/bean-validation/src/test/java/org/apache/struts/beanvalidation/actions/ModelDrivenAction.java
+++ 
b/plugins/bean-validation/src/test/java/org/apache/struts/beanvalidation/actions/ModelDrivenAction.java
@@ -21,7 +21,6 @@ package org.apache.struts.beanvalidation.actions;
 import com.opensymphony.xwork2.ActionSupport;
 import com.opensymphony.xwork2.ModelDriven;
 import org.apache.struts.beanvalidation.models.Person;
-import org.apache.struts2.interceptor.parameter.StrutsParameter;
 
 import javax.validation.Valid;
 
@@ -30,7 +29,6 @@ public class ModelDrivenAction extends ActionSupport 
implements ModelDriven<Pers
     @Valid
     private final Person model = new Person();
 
-    @StrutsParameter(depth = 2)
     @Override
     public Person getModel() {
         return model;
diff --git 
a/plugins/bean-validation/src/test/java/org/apache/struts/beanvalidation/actions/ValidateGroupAction.java
 
b/plugins/bean-validation/src/test/java/org/apache/struts/beanvalidation/actions/ValidateGroupAction.java
index 7d3540551..ff63256dc 100644
--- 
a/plugins/bean-validation/src/test/java/org/apache/struts/beanvalidation/actions/ValidateGroupAction.java
+++ 
b/plugins/bean-validation/src/test/java/org/apache/struts/beanvalidation/actions/ValidateGroupAction.java
@@ -22,7 +22,6 @@ import com.opensymphony.xwork2.ActionSupport;
 import com.opensymphony.xwork2.ModelDriven;
 import org.apache.struts.beanvalidation.constraints.ValidationGroup;
 import org.apache.struts.beanvalidation.models.Person;
-import org.apache.struts2.interceptor.parameter.StrutsParameter;
 
 import javax.validation.Valid;
 
@@ -31,7 +30,6 @@ public class ValidateGroupAction extends ActionSupport 
implements ModelDriven<Pe
     @Valid
     private final Person model = new Person();
 
-    @StrutsParameter(depth = 2)
     @Override
     public Person getModel() {
         return model;
diff --git 
a/plugins/junit/src/main/java/org/apache/struts2/junit/StrutsRestTestCase.java 
b/plugins/junit/src/main/java/org/apache/struts2/junit/StrutsRestTestCase.java
index 80a954f8e..82656edae 100644
--- 
a/plugins/junit/src/main/java/org/apache/struts2/junit/StrutsRestTestCase.java
+++ 
b/plugins/junit/src/main/java/org/apache/struts2/junit/StrutsRestTestCase.java
@@ -23,7 +23,6 @@ import com.opensymphony.xwork2.ActionProxy;
 import com.opensymphony.xwork2.ActionProxyFactory;
 import com.opensymphony.xwork2.config.Configuration;
 import org.apache.struts2.ServletActionContext;
-import org.apache.struts2.dispatcher.Dispatcher;
 import org.apache.struts2.dispatcher.HttpParameters;
 import org.apache.struts2.dispatcher.mapper.ActionMapping;
 import org.springframework.mock.web.MockHttpServletRequest;
@@ -75,7 +74,7 @@ public class StrutsRestTestCase<T> extends 
StrutsJUnit4TestCase<T> {
         ActionMapping mapping = getActionMapping(request);
 
         assertNotNull(mapping);
-        Dispatcher.getInstance().serviceAction(request, response, mapping);
+        dispatcher.serviceAction(request, response, mapping);
 
         if (response.getStatus() != HttpServletResponse.SC_OK)
             throw new ServletException("Error code [" + response.getStatus() + 
"], Error: ["
diff --git 
a/plugins/rest/src/test/java/org/apache/struts2/rest/RestActionInvocationTest.java
 
b/plugins/rest/src/test/java/org/apache/struts2/rest/RestActionInvocationTest.java
index 6f22a583e..432cb4a58 100644
--- 
a/plugins/rest/src/test/java/org/apache/struts2/rest/RestActionInvocationTest.java
+++ 
b/plugins/rest/src/test/java/org/apache/struts2/rest/RestActionInvocationTest.java
@@ -32,7 +32,6 @@ import com.opensymphony.xwork2.ognl.OgnlUtil;
 import com.opensymphony.xwork2.util.XWorkTestCaseHelper;
 import junit.framework.TestCase;
 import org.apache.struts2.ServletActionContext;
-import org.apache.struts2.interceptor.parameter.StrutsParameter;
 import org.apache.struts2.result.HttpHeaderResult;
 import org.springframework.mock.web.MockHttpServletRequest;
 import org.springframework.mock.web.MockHttpServletResponse;
@@ -47,97 +46,97 @@ import static 
javax.servlet.http.HttpServletResponse.SC_NOT_MODIFIED;
 
 public class RestActionInvocationTest extends TestCase {
 
-       RestActionInvocation restActionInvocation;
-       MockHttpServletRequest request;
-       MockHttpServletResponse response;
-
-       @Override
-       protected void setUp() throws Exception {
-               super.setUp();
-
-               restActionInvocation = new RestActionInvocationTester();
-               request = new MockHttpServletRequest();
-               response = new MockHttpServletResponse();
-               ServletActionContext.setRequest(request);
-               ServletActionContext.setResponse(response);
-
-       }
-
-       /**
-        * Test the correct action results: null, String, HttpHeaders, Result
-        * @throws Exception
-        */
-       public void testSaveResult() throws Exception {
-
-               Object methodResult = "index";
-               ActionConfig actionConfig = 
restActionInvocation.getProxy().getConfig();
-               assertEquals("index", 
restActionInvocation.saveResult(actionConfig, methodResult));
-
-               setUp();
-       methodResult = new DefaultHttpHeaders("show");
-       assertEquals("show", restActionInvocation.saveResult(actionConfig, 
methodResult));
-       assertEquals(methodResult, restActionInvocation.httpHeaders);
-
-               setUp();
-       methodResult = new HttpHeaderResult(HttpServletResponse.SC_ACCEPTED);
-       assertEquals(null, restActionInvocation.saveResult(actionConfig, 
methodResult));
-       assertEquals(methodResult, restActionInvocation.createResult());
-
-               setUp();
-       try {
-               methodResult = new Object();
-               restActionInvocation.saveResult(actionConfig, methodResult);
-
-               // ko
-               assertFalse(true);
-
-       } catch (ConfigurationException c) {
-               // ok, object not allowed
-       }
-       }
-
-       /**
-        * Test the target selection: exception, error messages, model and null
-        * @throws Exception
-        */
-       public void testSelectTarget() throws Exception {
-
-               // Exception
-               Exception e = new Exception();
-               restActionInvocation.getStack().set("exception", e);
-               restActionInvocation.selectTarget();
-               assertEquals(e, restActionInvocation.target);
-
-               // Error messages
-               setUp();
-               String actionMessage = "Error!";
-               RestActionSupport action = 
(RestActionSupport)restActionInvocation.getAction();
-               action.addActionError(actionMessage);
-               Map<String, Object> errors = new HashMap<String, Object>();
-               List<String> list = new ArrayList<String>();
-               list.add(actionMessage);
-       errors.put("actionErrors", list);
-       restActionInvocation.selectTarget();
-               assertEquals(errors, restActionInvocation.target);
-
-       // Model with get and no content in post, put, delete
-       setUp();
-               RestAction restAction = 
(RestAction)restActionInvocation.getAction();
-               List<String> model = new ArrayList<String>();
-               model.add("Item");
-               restAction.model = model;
-               request.setMethod("GET");
-               restActionInvocation.selectTarget();
-               assertEquals(model, restActionInvocation.target);
-               request.setMethod("POST");
-               restActionInvocation.selectTarget();
-               assertEquals(null, restActionInvocation.target);
-               request.setMethod("PUT");
-               restActionInvocation.selectTarget();
-               assertEquals(null, restActionInvocation.target);
-               request.setMethod("DELETE");
-               restActionInvocation.selectTarget();
-               assertEquals(null, restActionInvocation.target);
+    RestActionInvocation restActionInvocation;
+    MockHttpServletRequest request;
+    MockHttpServletResponse response;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        restActionInvocation = new RestActionInvocationTester();
+        request = new MockHttpServletRequest();
+        response = new MockHttpServletResponse();
+        ServletActionContext.setRequest(request);
+        ServletActionContext.setResponse(response);
+
+    }
+
+    /**
+     * Test the correct action results: null, String, HttpHeaders, Result
+     * @throws Exception
+     */
+    public void testSaveResult() throws Exception {
+
+        Object methodResult = "index";
+        ActionConfig actionConfig = 
restActionInvocation.getProxy().getConfig();
+        assertEquals("index", restActionInvocation.saveResult(actionConfig, 
methodResult));
+
+        setUp();
+        methodResult = new DefaultHttpHeaders("show");
+        assertEquals("show", restActionInvocation.saveResult(actionConfig, 
methodResult));
+        assertEquals(methodResult, restActionInvocation.httpHeaders);
+
+        setUp();
+        methodResult = new HttpHeaderResult(HttpServletResponse.SC_ACCEPTED);
+        assertEquals(null, restActionInvocation.saveResult(actionConfig, 
methodResult));
+        assertEquals(methodResult, restActionInvocation.createResult());
+
+        setUp();
+        try {
+            methodResult = new Object();
+            restActionInvocation.saveResult(actionConfig, methodResult);
+
+            // ko
+            assertFalse(true);
+
+        } catch (ConfigurationException c) {
+            // ok, object not allowed
+        }
+    }
+
+    /**
+     * Test the target selection: exception, error messages, model and null
+     * @throws Exception
+     */
+    public void testSelectTarget() throws Exception {
+
+        // Exception
+        Exception e = new Exception();
+        restActionInvocation.getStack().set("exception", e);
+        restActionInvocation.selectTarget();
+        assertEquals(e, restActionInvocation.target);
+
+        // Error messages
+        setUp();
+        String actionMessage = "Error!";
+        RestActionSupport action = 
(RestActionSupport)restActionInvocation.getAction();
+        action.addActionError(actionMessage);
+        Map<String, Object> errors = new HashMap<String, Object>();
+        List<String> list = new ArrayList<String>();
+        list.add(actionMessage);
+        errors.put("actionErrors", list);
+        restActionInvocation.selectTarget();
+        assertEquals(errors, restActionInvocation.target);
+
+        // Model with get and no content in post, put, delete
+        setUp();
+        RestAction restAction = (RestAction)restActionInvocation.getAction();
+        List<String> model = new ArrayList<String>();
+        model.add("Item");
+        restAction.model = model;
+        request.setMethod("GET");
+        restActionInvocation.selectTarget();
+        assertEquals(model, restActionInvocation.target);
+        request.setMethod("POST");
+        restActionInvocation.selectTarget();
+        assertEquals(null, restActionInvocation.target);
+        request.setMethod("PUT");
+        restActionInvocation.selectTarget();
+        assertEquals(null, restActionInvocation.target);
+        request.setMethod("DELETE");
+        restActionInvocation.selectTarget();
+        assertEquals(null, restActionInvocation.target);
 
         // disable content restriction to GET only
         model = new ArrayList<String>();
@@ -151,102 +150,100 @@ public class RestActionInvocationTest extends TestCase {
         assertEquals(model.get(0), "Item1");
     }
 
-       /**
-        * Test the not modified status code.
-        * @throws Exception
-        */
-       public void testResultNotModified() throws Exception {
+    /**
+     * Test the not modified status code.
+     * @throws Exception
+     */
+    public void testResultNotModified() throws Exception {
+
+        request.addHeader("If-None-Match", "123");
+        request.setMethod("GET");
+
+        RestAction restAction = (RestAction)restActionInvocation.getAction();
+        List<String> model = new ArrayList<String>() {
+            @Override
+            public int hashCode() {
+                return 123;
+            }
+        };
+        model.add("Item");
+        restAction.model = model;
+
+        restActionInvocation.processResult();
+        assertEquals(SC_NOT_MODIFIED, response.getStatus());
+
+    }
+
+    /**
+     * Test the default error result.
+     * @throws Exception
+     */
+    public void testDefaultErrorResult() throws Exception {
+
+        // Exception
+        Exception e = new Exception();
+        restActionInvocation.getStack().set("exception", e);
+        request.setMethod("GET");
+
+        RestAction restAction = (RestAction)restActionInvocation.getAction();
+        List<String> model = new ArrayList<String>();
+        model.add("Item");
+        restAction.model = model;
+
+        restActionInvocation.setDefaultErrorResultName("default-error");
+        ResultConfig resultConfig = new ResultConfig.Builder("default-error",
+                "org.apache.struts2.result.HttpHeaderResult")
+                .addParam("status", "123").build();
+        ActionConfig actionConfig = new ActionConfig.Builder("org.apache.rest",
+                "RestAction", "org.apache.rest.RestAction")
+                .addResultConfig(resultConfig)
+                .build();
+        
((MockActionProxy)restActionInvocation.getProxy()).setConfig(actionConfig);
+
+        restActionInvocation.processResult();
+        assertEquals(123, response.getStatus());
+
+    }
+
+    public void testNoResult() throws Exception {
 
-               request.addHeader("If-None-Match", "123");
-               request.setMethod("GET");
+        RestAction restAction = (RestAction)restActionInvocation.getAction();
+        List<String> model = new ArrayList<String>();
+        model.add("Item");
+        restAction.model = model;
+        request.setMethod("GET");
+        restActionInvocation.setResultCode("index");
 
-               RestAction restAction = 
(RestAction)restActionInvocation.getAction();
-               List<String> model = new ArrayList<String>() {
-                       @Override
-                       public int hashCode() {
-                               return 123;
-                       }
-               };
-               model.add("Item");
-               restAction.model = model;
+        try {
+            restActionInvocation.processResult();
 
-               restActionInvocation.processResult();
-               assertEquals(SC_NOT_MODIFIED, response.getStatus());
+            // ko
+            assertFalse(true);
+
+        } catch (ConfigurationException c) {
+            // ok, no result
+        }
 
     }
 
-       /**
-        * Test the default error result.
-        * @throws Exception
-        */
-       public void testDefaultErrorResult() throws Exception {
-
-               // Exception
-               Exception e = new Exception();
-               restActionInvocation.getStack().set("exception", e);
-               request.setMethod("GET");
-
-               RestAction restAction = 
(RestAction)restActionInvocation.getAction();
-               List<String> model = new ArrayList<String>();
-               model.add("Item");
-               restAction.model = model;
-
-               restActionInvocation.setDefaultErrorResultName("default-error");
-               ResultConfig resultConfig = new 
ResultConfig.Builder("default-error",
-                       "org.apache.struts2.result.HttpHeaderResult")
-               .addParam("status", "123").build();
-           ActionConfig actionConfig = new 
ActionConfig.Builder("org.apache.rest",
-                               "RestAction", "org.apache.rest.RestAction")
-               .addResultConfig(resultConfig)
-               .build();
-           
((MockActionProxy)restActionInvocation.getProxy()).setConfig(actionConfig);
-
-               restActionInvocation.processResult();
-               assertEquals(123, response.getStatus());
-
-       }
-
-       public void testNoResult() throws Exception {
-
-               RestAction restAction = 
(RestAction)restActionInvocation.getAction();
-               List<String> model = new ArrayList<String>();
-               model.add("Item");
-               restAction.model = model;
-               request.setMethod("GET");
-               restActionInvocation.setResultCode("index");
-
-               try {
-                       restActionInvocation.processResult();
-
-               // ko
-               assertFalse(true);
-
-       } catch (ConfigurationException c) {
-               // ok, no result
-       }
-
-       }
-
-       /**
-        * Test the global execution
-        * @throws Exception
-        */
-       public void testInvoke() throws Exception {
-
-           // Default index method return 'success'
-           
((MockActionProxy)restActionInvocation.getProxy()).setMethod("index");
-
-           // Define result 'success'
-               ResultConfig resultConfig = new ResultConfig.Builder("success",
-                       "org.apache.struts2.result.HttpHeaderResult")
-               .addParam("status", "123").build();
-           ActionConfig actionConfig = new 
ActionConfig.Builder("org.apache.rest",
-                               "RestAction", "org.apache.rest.RestAction")
-               .addResultConfig(resultConfig)
-               .build();
-           
((MockActionProxy)restActionInvocation.getProxy()).setConfig(actionConfig);
-
-               request.setMethod("GET");
+    /**
+     * Test the global execution
+     * @throws Exception
+     */
+    public void testInvoke() throws Exception {
+
+        // Default index method return 'success'
+        ((MockActionProxy)restActionInvocation.getProxy()).setMethod("index");
+
+        // Define result 'success'
+        ResultConfig resultConfig = new ResultConfig.Builder("success", 
"org.apache.struts2.result.HttpHeaderResult")
+                .addParam("status", "123").build();
+        ActionConfig actionConfig = new 
ActionConfig.Builder("org.apache.rest", "RestAction", 
"org.apache.rest.RestAction")
+                .addResultConfig(resultConfig)
+                .build();
+        
((MockActionProxy)restActionInvocation.getProxy()).setConfig(actionConfig);
+
+        request.setMethod("GET");
 
         restActionInvocation.setOgnlUtil(new OgnlUtil());
         restActionInvocation.invoke();
@@ -256,31 +253,31 @@ public class RestActionInvocationTest extends TestCase {
 
 
     class RestActionInvocationTester extends RestActionInvocation {
-       RestActionInvocationTester() {
-            super(new HashMap<String, Object>(), true);
-            List<InterceptorMapping> interceptorMappings = new 
ArrayList<InterceptorMapping>();
+        RestActionInvocationTester() {
+            super(new HashMap<>(), true);
+            List<InterceptorMapping> interceptorMappings = new ArrayList<>();
             MockInterceptor mockInterceptor = new MockInterceptor();
             mockInterceptor.setFoo("interceptor");
             mockInterceptor.setExpectedFoo("interceptor");
             interceptorMappings.add(new InterceptorMapping("interceptor", 
mockInterceptor));
             interceptors = interceptorMappings.iterator();
             MockActionProxy actionProxy = new MockActionProxy();
-            ActionConfig actionConfig = new 
ActionConfig.Builder("org.apache.rest",
-                               "RestAction", 
"org.apache.rest.RestAction").build();
+            ActionConfig actionConfig = new ActionConfig.Builder(
+                    "org.apache.rest", "RestAction", 
"org.apache.rest.RestAction").build();
             actionProxy.setConfig(actionConfig);
             proxy = actionProxy;
             action = new RestAction();
             setMimeTypeHandlerSelector(new DefaultContentTypeHandlerManager());
             unknownHandlerManager = new DefaultUnknownHandlerManager();
-                       try {
-                               XWorkTestCaseHelper.setUp();
-                       } catch (Exception e) {
-                               throw new RuntimeException(e);
-                       }
-                       invocationContext = ActionContext.getContext();
-                       container = ActionContext.getContext().getContainer();
-                       stack = ActionContext.getContext().getValueStack();
-                       objectFactory = 
container.getInstance(ObjectFactory.class);
+            try {
+                XWorkTestCaseHelper.setUp();
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+            invocationContext = ActionContext.getContext();
+            container = ActionContext.getContext().getContainer();
+            stack = ActionContext.getContext().getValueStack();
+            objectFactory = container.getInstance(ObjectFactory.class);
 
         }
 
@@ -288,13 +285,12 @@ public class RestActionInvocationTest extends TestCase {
 
     static class RestAction extends RestActionSupport implements 
ModelDriven<List<String>> {
 
-       List<String> model;
+        List<String> model;
 
-               @StrutsParameter(depth = 1)
-               @Override
-       public List<String> getModel() {
-                       return model;
-               }
+        @Override
+        public List<String> getModel() {
+            return model;
+        }
 
     }
 }
diff --git 
a/plugins/spring/src/test/java/com/opensymphony/xwork2/ModelDrivenAction.java 
b/plugins/spring/src/test/java/com/opensymphony/xwork2/ModelDrivenAction.java
index 6ffcad2ff..e300d036b 100644
--- 
a/plugins/spring/src/test/java/com/opensymphony/xwork2/ModelDrivenAction.java
+++ 
b/plugins/spring/src/test/java/com/opensymphony/xwork2/ModelDrivenAction.java
@@ -44,9 +44,8 @@ public class ModelDrivenAction extends ActionSupport 
implements ModelDriven {
     /**
      * @return the model to be pushed onto the ValueStack after the Action 
itself
      */
-    @StrutsParameter(depth = 2)
     @Override
-    public Object getModel() {
+    public TestBean getModel() {
         return model;
     }
 }


Reply via email to