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

kusal pushed a commit to branch WW-5352-parameter-annotation-4
in repository https://gitbox.apache.org/repos/asf/struts.git

commit 805f2ba724cd04870cc2d00932dceb8a50e98b46
Author: Kusal Kithul-Godage <g...@kusal.io>
AuthorDate: Tue Jan 30 01:47:30 2024 +1100

    WW-5352 Ensure StrutsParameter compatibility with TypeConversion setters
---
 .../xwork2/ognl/SecurityMemberAccess.java          |  8 ++-
 .../parameter/ParametersInterceptor.java           | 59 +++++++++++++---------
 .../parameter/StrutsParameterAnnotationTest.java   | 22 ++++++++
 3 files changed, 65 insertions(+), 24 deletions(-)

diff --git 
a/core/src/main/java/com/opensymphony/xwork2/ognl/SecurityMemberAccess.java 
b/core/src/main/java/com/opensymphony/xwork2/ognl/SecurityMemberAccess.java
index 510a65c60..0776c90b7 100644
--- a/core/src/main/java/com/opensymphony/xwork2/ognl/SecurityMemberAccess.java
+++ b/core/src/main/java/com/opensymphony/xwork2/ognl/SecurityMemberAccess.java
@@ -67,12 +67,18 @@ public class SecurityMemberAccess implements MemberAccess {
     )));
 
     private static final Set<Class<?>> ALLOWLIST_REQUIRED_CLASSES = 
unmodifiableSet(new HashSet<>(Arrays.asList(
+            com.opensymphony.xwork2.conversion.impl.XWorkList.class,
             java.lang.Enum.class,
             java.lang.String.class,
+            java.util.ArrayList.class,
+            java.util.Collection.class,
             java.util.Date.class,
             java.util.HashMap.class,
+            java.util.HashSet.class,
+            java.util.List.class,
             java.util.Map.class,
-            java.util.Map.Entry.class
+            java.util.Map.Entry.class,
+            java.util.Set.class
     )));
 
     private final ProviderAllowlist providerAllowlist;
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 e9215e533..2766bc36c 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
@@ -51,7 +51,6 @@ import java.beans.Introspector;
 import java.beans.PropertyDescriptor;
 import java.lang.reflect.AnnotatedElement;
 import java.lang.reflect.Field;
-import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
@@ -368,7 +367,14 @@ public class ParametersInterceptor extends 
MethodFilterInterceptor {
         String rootProperty = nestingIndex == -1 ? name : name.substring(0, 
nestingIndex);
         String normalisedRootProperty = 
Character.toLowerCase(rootProperty.charAt(0)) + rootProperty.substring(1);
 
-        return hasValidAnnotatedMember(normalisedRootProperty, action, 
paramDepth);
+        boolean result = hasValidAnnotatedMember(normalisedRootProperty, 
action, paramDepth);
+        if (!result) {
+            LOG.debug(
+                    "Parameter injection for root property [{}] on action [{}] 
rejected. Ensure the corresponding getter or setter is annotated with 
@StrutsParameter with an appropriate 'depth'.",
+                    normalisedRootProperty,
+                    action.getClass().getName());
+        }
+        return result;
     }
 
     /**
@@ -396,28 +402,39 @@ public class ParametersInterceptor extends 
MethodFilterInterceptor {
     }
 
     protected boolean hasValidAnnotatedPropertyDescriptor(PropertyDescriptor 
propDesc, long paramDepth) {
-        Method relevantMethod = paramDepth == 0 ? propDesc.getWriteMethod() : 
propDesc.getReadMethod();
-        if (relevantMethod == null) {
-            return false;
-        }
-        if (getPermittedInjectionDepth(relevantMethod) < paramDepth) {
-            LOG.debug(
-                    "Parameter injection for method [{}] on action [{}] 
rejected. Ensure it is annotated with @StrutsParameter with an appropriate 
'depth'.",
-                    relevantMethod.getName(),
-                    relevantMethod.getDeclaringClass().getName());
-            return false;
+        int permittedDepth = -1;
+        if (paramDepth > 0 && propDesc.getReadMethod() != null) {
+            permittedDepth = 
getPermittedInjectionDepth(propDesc.getReadMethod());
         }
-        if (paramDepth >= 1) {
-            allowlistClass(relevantMethod.getReturnType());
+        if (permittedDepth == -1 && propDesc.getWriteMethod() != null) {
+            permittedDepth = 
getPermittedInjectionDepth(propDesc.getWriteMethod());
         }
-        if (paramDepth >= 2) {
-            allowlistReturnTypeIfParameterized(relevantMethod);
+
+        if (permittedDepth < paramDepth) {
+            return false;
         }
+
+        autoAllowlistTypes(propDesc, paramDepth);
         return true;
     }
 
-    protected void allowlistReturnTypeIfParameterized(Method method) {
-        allowlistParameterizedTypeArg(method.getGenericReturnType());
+    protected void autoAllowlistTypes(PropertyDescriptor propDesc, long 
paramDepth) {
+        if (propDesc.getReadMethod() != null) {
+            if (paramDepth >= 1) {
+                allowlistClass(propDesc.getReadMethod().getReturnType());
+            }
+            if (paramDepth >= 2) {
+                
allowlistParameterizedTypeArg(propDesc.getReadMethod().getGenericReturnType());
+            }
+        }
+        if (propDesc.getWriteMethod() != null) {
+            if (paramDepth >= 1) {
+                
allowlistClass(propDesc.getWriteMethod().getParameterTypes()[0]);
+            }
+            if (paramDepth >= 2) {
+                
allowlistParameterizedTypeArg(propDesc.getWriteMethod().getGenericParameterTypes()[0]);
+            }
+        }
     }
 
     protected void allowlistParameterizedTypeArg(Type genericType) {
@@ -465,15 +482,11 @@ public class ParametersInterceptor extends 
MethodFilterInterceptor {
             allowlistClass(field.getType());
         }
         if (paramDepth >= 2) {
-            allowlistFieldIfParameterized(field);
+            allowlistParameterizedTypeArg(field.getGenericType());
         }
         return true;
     }
 
-    protected void allowlistFieldIfParameterized(Field field) {
-        allowlistParameterizedTypeArg(field.getGenericType());
-    }
-
     /**
      * @return permitted injection depth where -1 indicates not permitted
      */
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..e8d51d31a 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
@@ -246,6 +246,17 @@ public class StrutsParameterAnnotationTest {
         
assertThat(threadAllowlist.getAllowlist()).containsExactlyInAnyOrderElementsOf(getParentClasses(Map.class,
 String.class, Pojo.class));
     }
 
+    @Test
+    public void setterPojoListDepthOneMethod() {
+        testParameter(new SetterOnlyAction(), "pojosDepthOne[0].key", false);
+    }
+
+    @Test
+    public void setterPojoListDepthTwoMethod() {
+        testParameter(new SetterOnlyAction(), "pojosDepthTwo[0].key", true);
+        
assertThat(threadAllowlist.getAllowlist()).containsExactlyInAnyOrderElementsOf(getParentClasses(List.class,
 Pojo.class));
+    }
+
     @Test
     public void publicStrNotAnnotated_transitionMode() {
         
parametersInterceptor.setRequireAnnotationsTransitionMode(Boolean.TRUE.toString());
@@ -343,6 +354,17 @@ public class StrutsParameterAnnotationTest {
         }
     }
 
+    class SetterOnlyAction {
+
+        @StrutsParameter(depth = 1)
+        public void setPojosDepthOne(List<Pojo> pojos) {
+        }
+
+        @StrutsParameter(depth = 2)
+        public void setPojosDepthTwo(List<Pojo> pojos) {
+        }
+    }
+
     class Pojo {
     }
 }

Reply via email to