This is an automated email from the ASF dual-hosted git repository. kusal pushed a commit to branch fix/WW-5468-modeldriven-kusal in repository https://gitbox.apache.org/repos/asf/struts.git
commit f67f593bdb96398996fd663fefc2c1ddedc1740a Author: Kusal Kithul-Godage <g...@kusal.io> AuthorDate: Fri Oct 11 20:56:33 2024 +1100 WW-5468 Alternate fix for ModelDriven Action parameters --- core/src/main/java/com/opensymphony/xwork2/ModelDriven.java | 6 ++++++ .../interceptor/parameter/ParametersInterceptor.java | 8 +++++++- .../parameter/StrutsParameterAnnotationTest.java | 13 ++++++++++--- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/com/opensymphony/xwork2/ModelDriven.java b/core/src/main/java/com/opensymphony/xwork2/ModelDriven.java index c07c6bbe7..fc7f9a348 100644 --- a/core/src/main/java/com/opensymphony/xwork2/ModelDriven.java +++ b/core/src/main/java/com/opensymphony/xwork2/ModelDriven.java @@ -18,6 +18,8 @@ */ package com.opensymphony.xwork2; +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 353f3cb82..5ff5be262 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 @@ -20,6 +20,7 @@ package org.apache.struts2.interceptor.parameter; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionInvocation; +import com.opensymphony.xwork2.ModelDriven; import com.opensymphony.xwork2.inject.Inject; import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor; import com.opensymphony.xwork2.security.AcceptedPatternsChecker; @@ -348,6 +349,11 @@ 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)) { + return hasValidAnnotatedMember("model", action, paramDepth + 1); + } + if (requireAnnotationsTransitionMode && paramDepth == 0) { return true; } @@ -401,7 +407,7 @@ public class ParametersInterceptor extends MethodFilterInterceptor { return false; } if (paramDepth >= 1) { - allowlistClass(relevantMethod.getReturnType()); + allowlistClass(propDesc.getPropertyType()); } if (paramDepth >= 2) { allowlistReturnTypeIfParameterized(relevantMethod); 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 eb44fc6fe..256b16eca 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,7 +18,9 @@ */ 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 org.apache.commons.lang3.ClassUtils; @@ -64,6 +66,7 @@ public class StrutsParameterAnnotationTest { @After public void tearDown() throws Exception { threadAllowlist.clearAllowlist(); + ActionContext.clear(); } private void testParameter(Object action, String paramName, boolean shouldContain) { @@ -261,8 +264,13 @@ public class StrutsParameterAnnotationTest { @Test public void publicModelPojo() { - parametersInterceptor.setRequireAnnotationsTransitionMode(Boolean.TRUE.toString()); - testParameter(new ModelAction(), "name", true); + var action = new ModelAction(); + var 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)); } @@ -352,7 +360,6 @@ public class StrutsParameterAnnotationTest { static class ModelAction implements ModelDriven<Pojo> { - @StrutsParameter public Pojo getModel() { return new Pojo(); }