diff --git a/core/src/main/java/org/apache/struts2/ognl/OgnlNullHandlerWrapper.java b/core/src/main/java/org/apache/struts2/ognl/OgnlNullHandlerWrapper.java index a90c932313..4c05b24d49 100644 --- a/core/src/main/java/org/apache/struts2/ognl/OgnlNullHandlerWrapper.java +++ b/core/src/main/java/org/apache/struts2/ognl/OgnlNullHandlerWrapper.java @@ -18,10 +18,9 @@ */ package org.apache.struts2.ognl; -import ognl.OgnlContext; import org.apache.struts2.conversion.NullHandler; -public class OgnlNullHandlerWrapper implements ognl.NullHandler { +public class OgnlNullHandlerWrapper implements ognl.NullHandler { private final NullHandler wrapped; @@ -30,13 +29,13 @@ public OgnlNullHandlerWrapper(NullHandler target) { } @Override - public Object nullMethodResult(OgnlContext context, Object target, + public Object nullMethodResult(StrutsContext context, Object target, String methodName, Object[] args) { return wrapped.nullMethodResult(context, target, methodName, args); } @Override - public Object nullPropertyValue(OgnlContext context, Object target, Object property) { + public Object nullPropertyValue(StrutsContext context, Object target, Object property) { return wrapped.nullPropertyValue(context, target, property); } diff --git a/core/src/main/java/org/apache/struts2/ognl/OgnlReflectionContextFactory.java b/core/src/main/java/org/apache/struts2/ognl/OgnlReflectionContextFactory.java index 62dab60a38..ed79b2fbf4 100644 --- a/core/src/main/java/org/apache/struts2/ognl/OgnlReflectionContextFactory.java +++ b/core/src/main/java/org/apache/struts2/ognl/OgnlReflectionContextFactory.java @@ -29,6 +29,7 @@ public class OgnlReflectionContextFactory implements ReflectionContextFactory { @Override + @SuppressWarnings({"rawtypes", "unchecked"}) public OgnlContext createDefaultContext(Object root) { return Ognl.createDefaultContext(root); } diff --git a/core/src/main/java/org/apache/struts2/ognl/OgnlTypeConverterWrapper.java b/core/src/main/java/org/apache/struts2/ognl/OgnlTypeConverterWrapper.java index 8aad8972b0..7a5023cfe9 100644 --- a/core/src/main/java/org/apache/struts2/ognl/OgnlTypeConverterWrapper.java +++ b/core/src/main/java/org/apache/struts2/ognl/OgnlTypeConverterWrapper.java @@ -18,7 +18,6 @@ */ package org.apache.struts2.ognl; -import ognl.OgnlContext; import org.apache.struts2.conversion.TypeConverter; import java.lang.reflect.Member; @@ -26,7 +25,7 @@ /** * Wraps an XWork type conversion class for as an OGNL TypeConverter */ -public class OgnlTypeConverterWrapper implements ognl.TypeConverter { +public class OgnlTypeConverterWrapper implements ognl.TypeConverter { private final TypeConverter typeConverter; @@ -38,7 +37,7 @@ public OgnlTypeConverterWrapper(TypeConverter converter) { } @Override - public Object convertValue(OgnlContext context, Object target, Member member, String propertyName, Object value, Class toType) { + public Object convertValue(StrutsContext context, Object target, Member member, String propertyName, Object value, Class toType) { return typeConverter.convertValue(context, target, member, propertyName, value, toType); } diff --git a/core/src/main/java/org/apache/struts2/ognl/OgnlUtil.java b/core/src/main/java/org/apache/struts2/ognl/OgnlUtil.java index f9e4842027..cec398f0b9 100644 --- a/core/src/main/java/org/apache/struts2/ognl/OgnlUtil.java +++ b/core/src/main/java/org/apache/struts2/ognl/OgnlUtil.java @@ -61,7 +61,7 @@ public class OgnlUtil { private final OgnlCache expressionCache; private final OgnlCache, BeanInfo> beanInfoCache; - private TypeConverter defaultConverter; + private TypeConverter defaultConverter; private final OgnlGuard ognlGuard; private boolean devMode; @@ -211,14 +211,14 @@ public int beanInfoCacheSize() { * @return an OgnlContext instance * @since 7.2.0 */ - private OgnlContext ensureOgnlContext(Map context) { - if (context instanceof OgnlContext ognlContext) { - return ognlContext; + private StrutsContext ensureOgnlContext(Map context) { + if (context instanceof StrutsContext strutsContext) { + return strutsContext; } - // Create a new OgnlContext and copy the Map contents - OgnlContext ognlContext = createDefaultContext(null); - ognlContext.putAll(context); - return ognlContext; + // Create a new StrutsContext and copy the Map contents + StrutsContext strutsContext = createDefaultContext(null); + strutsContext.putAll(context); + return strutsContext; } /** @@ -247,9 +247,9 @@ public void setProperties(Map props, Object o, Map co return; } - OgnlContext ognlContext = ensureOgnlContext(context); + StrutsContext strutsContext = ensureOgnlContext(context); try { - withRoot(ognlContext, o, () -> { + withRoot(strutsContext, o, () -> { for (Map.Entry entry : props.entrySet()) { String expression = entry.getKey(); internalSetProperty(expression, entry.getValue(), o, context, throwPropertyExceptions); @@ -309,9 +309,9 @@ public void setProperty(String name, Object value, Object o, Map * problems setting the property */ public void setProperty(String name, Object value, Object o, Map context, boolean throwPropertyExceptions) { - OgnlContext ognlContext = ensureOgnlContext(context); + StrutsContext strutsContext = ensureOgnlContext(context); try { - withRoot(ognlContext, o, () -> internalSetProperty(name, value, o, context, throwPropertyExceptions)); + withRoot(strutsContext, o, () -> internalSetProperty(name, value, o, context, throwPropertyExceptions)); } catch (OgnlException e) { // Should never happen as internalSetProperty catches OgnlException throw new IllegalStateException("Unexpected OgnlException in setProperty", e); @@ -424,7 +424,7 @@ private void ognlSet(String expr, Map context, Object root, Obje for (TreeValidator validator : treeValidators) { validator.validate(tree, checkContext); } - OgnlContext ognlContext = (OgnlContext) context; + StrutsContext ognlContext = (StrutsContext) context; withRoot(ognlContext, root, () -> Ognl.setValue(tree, ognlContext, root, value)); } @@ -434,7 +434,7 @@ private T ognlGet(String expr, Map context, Object root, Cla for (TreeValidator validator : treeValidators) { validator.validate(tree, checkContext); } - OgnlContext ognlContext = (OgnlContext) context; + StrutsContext ognlContext = (StrutsContext) context; return withRoot(ognlContext, root, () -> (T) Ognl.getValue(tree, ognlContext, root, resultType)); } @@ -548,8 +548,8 @@ public void copy(final Object from, return; } - final Map contextFrom = createDefaultContext(from); - final Map contextTo = createDefaultContext(to); + final StrutsContext contextFrom = createDefaultContext(from); + final StrutsContext contextTo = createDefaultContext(to); PropertyDescriptor[] fromPds; PropertyDescriptor[] toPds; @@ -654,7 +654,7 @@ public PropertyDescriptor[] getPropertyDescriptors(Class clazz) throws Intros */ public Map getBeanMap(final Object source) throws IntrospectionException, OgnlException { Map beanMap = new HashMap<>(); - final Map sourceMap = createDefaultContext(source); + final StrutsContext sourceMap = createDefaultContext(source); PropertyDescriptor[] propertyDescriptors = getPropertyDescriptors(source); for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { final String propertyName = propertyDescriptor.getDisplayName(); @@ -724,18 +724,21 @@ void internalSetProperty(String name, Object value, Object o, Map resolver) { if (resolver == null) { resolver = container.getInstance(RootAccessor.class); if (resolver == null) { throw new IllegalStateException("Cannot find ClassResolver"); } } - return Ognl.createDefaultContext(root, container.getInstance(SecurityMemberAccess.class), resolver, defaultConverter); + StrutsContext context = new StrutsContext( + container.getInstance(SecurityMemberAccess.class), resolver, defaultConverter); + context.withRoot(root); + return context; } @FunctionalInterface @@ -762,13 +765,13 @@ private interface OgnlSupplier { * @param action the action to execute * @throws OgnlException if the action throws an OgnlException */ - private void withRoot(OgnlContext context, Object root, OgnlAction action) throws OgnlException { - Object oldRoot = Ognl.getRoot(context); + private void withRoot(StrutsContext context, Object root, OgnlAction action) throws OgnlException { + Object oldRoot = context.getRoot(); try { - Ognl.setRoot(context, root); + context.withRoot(root); action.run(); } finally { - Ognl.setRoot(context, oldRoot); + context.withRoot(oldRoot); } } @@ -783,13 +786,13 @@ private void withRoot(OgnlContext context, Object root, OgnlAction action) throw * @return the result of the supplier * @throws OgnlException if the supplier throws an OgnlException */ - private T withRoot(OgnlContext context, Object root, OgnlSupplier supplier) throws OgnlException { - Object oldRoot = Ognl.getRoot(context); + private T withRoot(StrutsContext context, Object root, OgnlSupplier supplier) throws OgnlException { + Object oldRoot = context.getRoot(); try { - Ognl.setRoot(context, root); + context.withRoot(root); return supplier.get(); } finally { - Ognl.setRoot(context, oldRoot); + context.withRoot(oldRoot); } } } diff --git a/core/src/main/java/org/apache/struts2/ognl/OgnlValueStack.java b/core/src/main/java/org/apache/struts2/ognl/OgnlValueStack.java index 2376a418f3..fc8a9d33f3 100644 --- a/core/src/main/java/org/apache/struts2/ognl/OgnlValueStack.java +++ b/core/src/main/java/org/apache/struts2/ognl/OgnlValueStack.java @@ -31,8 +31,6 @@ import org.apache.struts2.util.reflection.ReflectionContextState; import ognl.MethodFailedException; import ognl.NoSuchPropertyException; -import ognl.Ognl; -import ognl.OgnlContext; import ognl.OgnlException; import org.apache.commons.lang3.BooleanUtils; import org.apache.logging.log4j.LogManager; @@ -68,7 +66,7 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS private static final String MAP_IDENTIFIER_KEY = "org.apache.struts2.util.OgnlValueStack.MAP_IDENTIFIER_KEY"; protected CompoundRoot root; - protected transient Map context; + protected transient StrutsContext context; protected Class defaultType; protected Map overrides; protected transient OgnlUtil ognlUtil; @@ -121,12 +119,12 @@ protected void setOgnlUtil(OgnlUtil ognlUtil) { protected void setRoot(XWorkConverter xworkConverter, RootAccessor accessor, CompoundRoot compoundRoot, SecurityMemberAccess securityMemberAccess) { this.root = compoundRoot; this.securityMemberAccess = securityMemberAccess; - OgnlContext ognlContext = Ognl.createDefaultContext(this.root, securityMemberAccess, accessor, new OgnlTypeConverterWrapper(xworkConverter)); - this.context = ognlContext; + this.context = new StrutsContext(securityMemberAccess, accessor, new OgnlTypeConverterWrapper(xworkConverter)); + this.context.withRoot(this.root); this.converter = xworkConverter; context.put(VALUE_STACK, this); - ognlContext.setTraceEvaluations(false); - ognlContext.setKeepLastEvaluation(false); + context.setTraceEvaluations(false); + context.setKeepLastEvaluation(false); } @Inject(StrutsConstants.STRUTS_DEVMODE) @@ -508,9 +506,7 @@ private Object readResolve() { @Override public void clearContextValues() { - //this is an OGNL ValueStack so the context will be an OgnlContext - //it would be better to make context of type OgnlContext - ((OgnlContext) context).getValues().clear(); + context.getValues().clear(); } @Override diff --git a/core/src/main/java/org/apache/struts2/ognl/OgnlValueStackFactory.java b/core/src/main/java/org/apache/struts2/ognl/OgnlValueStackFactory.java index ac60de0dca..eb9f39749a 100644 --- a/core/src/main/java/org/apache/struts2/ognl/OgnlValueStackFactory.java +++ b/core/src/main/java/org/apache/struts2/ognl/OgnlValueStackFactory.java @@ -54,6 +54,7 @@ protected void setXWorkConverter(XWorkConverter converter) { } @Inject + @SuppressWarnings({"rawtypes", "unchecked"}) protected void setCompoundRootAccessor(RootAccessor compoundRootAccessor) { this.compoundRootAccessor = compoundRootAccessor; OgnlRuntime.setPropertyAccessor(CompoundRoot.class, compoundRootAccessor); @@ -110,6 +111,7 @@ protected void setContainer(Container container) throws ClassNotFoundException { * {@link #setMethodAccessor} and can be configured using the extension point * {@link StrutsConstants#STRUTS_METHOD_ACCESSOR}. */ + @SuppressWarnings({"rawtypes", "unchecked"}) protected void registerAdditionalMethodAccessors() { Set names = container.getInstanceNames(MethodAccessor.class); for (String name : names) { @@ -145,6 +147,7 @@ protected void registerNullHandlers() throws ClassNotFoundException { } } + @SuppressWarnings({"rawtypes", "unchecked"}) protected void registerPropertyAccessors() throws ClassNotFoundException { Set names = container.getInstanceNames(PropertyAccessor.class); for (String name : names) { diff --git a/core/src/main/java/org/apache/struts2/ognl/SecurityMemberAccess.java b/core/src/main/java/org/apache/struts2/ognl/SecurityMemberAccess.java index d25bbe3774..424cec9c64 100644 --- a/core/src/main/java/org/apache/struts2/ognl/SecurityMemberAccess.java +++ b/core/src/main/java/org/apache/struts2/ognl/SecurityMemberAccess.java @@ -19,7 +19,6 @@ package org.apache.struts2.ognl; import ognl.MemberAccess; -import ognl.OgnlContext; import org.apache.commons.lang3.BooleanUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -54,7 +53,7 @@ * Allows access decisions to be made on the basis of whether a member is static or not. * Also blocks or allows access to properties. */ -public class SecurityMemberAccess implements MemberAccess { +public class SecurityMemberAccess implements MemberAccess { private static final Logger LOG = LogManager.getLogger(SecurityMemberAccess.class); @@ -115,7 +114,7 @@ public void setProxyService(ProxyService proxyService) { } @Override - public Object setup(OgnlContext context, Object target, Member member, String propertyName) { + public Object setup(StrutsContext context, Object target, Member member, String propertyName) { Object result = null; if (isAccessible(context, target, member, propertyName)) { @@ -130,7 +129,7 @@ public Object setup(OgnlContext context, Object target, Member member, String pr } @Override - public void restore(OgnlContext context, Object target, Member member, String propertyName, Object state) { + public void restore(StrutsContext context, Object target, Member member, String propertyName, Object state) { if (state == null) { return; } @@ -145,7 +144,7 @@ public void restore(OgnlContext context, Object target, Member member, String pr } @Override - public boolean isAccessible(OgnlContext context, Object target, Member member, String propertyName) { + public boolean isAccessible(StrutsContext context, Object target, Member member, String propertyName) { LOG.debug("Checking access for [target: {}, member: {}, property: {}]", target, member, propertyName); if (member == null) { diff --git a/core/src/main/java/org/apache/struts2/ognl/StrutsContext.java b/core/src/main/java/org/apache/struts2/ognl/StrutsContext.java new file mode 100644 index 0000000000..e2b7b4b930 --- /dev/null +++ b/core/src/main/java/org/apache/struts2/ognl/StrutsContext.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.struts2.ognl; + +import ognl.ClassResolver; +import ognl.MemberAccess; +import ognl.OgnlContext; +import ognl.TypeConverter; + +/** + * Struts-specific OGNL evaluation context. Extends {@link OgnlContext} with the + * self-bounded generic parameter to enable type-safe access in all OGNL interface + * implementations ({@link MemberAccess}, {@link ognl.PropertyAccessor}, etc.). + * + *

Phase 1: minimal subclass delegating to super constructors. + * Future phases will promote stringly-typed map entries (e.g. {@code DENY_METHOD_EXECUTION}, + * {@code CREATE_NULL_OBJECTS}) to proper typed fields.

+ * + * @since 7.2.0 + */ +public class StrutsContext extends OgnlContext { + + public StrutsContext(MemberAccess memberAccess) { + super(memberAccess); + } + + public StrutsContext(MemberAccess memberAccess, + ClassResolver classResolver) { + super(memberAccess, classResolver); + } + + public StrutsContext(MemberAccess memberAccess, + ClassResolver classResolver, + TypeConverter typeConverter) { + super(memberAccess, classResolver, typeConverter); + } +} diff --git a/core/src/main/java/org/apache/struts2/ognl/XWorkTypeConverterWrapper.java b/core/src/main/java/org/apache/struts2/ognl/XWorkTypeConverterWrapper.java index 49112ab12c..49ede9405c 100644 --- a/core/src/main/java/org/apache/struts2/ognl/XWorkTypeConverterWrapper.java +++ b/core/src/main/java/org/apache/struts2/ognl/XWorkTypeConverterWrapper.java @@ -18,7 +18,6 @@ */ package org.apache.struts2.ognl; -import ognl.OgnlContext; import org.apache.struts2.conversion.TypeConverter; import java.lang.reflect.Member; @@ -29,19 +28,19 @@ */ public class XWorkTypeConverterWrapper implements TypeConverter { - private final ognl.TypeConverter typeConverter; + private final ognl.TypeConverter typeConverter; - public XWorkTypeConverterWrapper(ognl.TypeConverter conv) { + public XWorkTypeConverterWrapper(ognl.TypeConverter conv) { this.typeConverter = conv; } @Override public Object convertValue(Map context, Object target, Member member, String propertyName, Object value, Class toType) { - // Cast context to OgnlContext for OGNL 3.4.8+ compatibility - OgnlContext ognlContext = (context instanceof OgnlContext oc) ? oc : null; - if (ognlContext == null) { - throw new IllegalArgumentException("Context must be an OgnlContext for OGNL 3.4.8+"); + // Cast context to StrutsContext for OGNL 3.5.x compatibility + StrutsContext strutsContext = (context instanceof StrutsContext sc) ? sc : null; + if (strutsContext == null) { + throw new IllegalArgumentException("Context must be a StrutsContext for OGNL 3.5.x+"); } - return typeConverter.convertValue(ognlContext, target, member, propertyName, value, toType); + return typeConverter.convertValue(strutsContext, target, member, propertyName, value, toType); } } diff --git a/core/src/main/java/org/apache/struts2/ognl/accessor/CompoundRootAccessor.java b/core/src/main/java/org/apache/struts2/ognl/accessor/CompoundRootAccessor.java index 801be939bd..4b7f90a7a5 100644 --- a/core/src/main/java/org/apache/struts2/ognl/accessor/CompoundRootAccessor.java +++ b/core/src/main/java/org/apache/struts2/ognl/accessor/CompoundRootAccessor.java @@ -26,7 +26,6 @@ import ognl.MethodFailedException; import ognl.NoSuchPropertyException; import ognl.Ognl; -import ognl.OgnlContext; import ognl.OgnlException; import ognl.OgnlRuntime; import org.apache.commons.lang3.BooleanUtils; @@ -34,6 +33,7 @@ import org.apache.logging.log4j.Logger; import org.apache.struts2.StrutsConstants; import org.apache.struts2.StrutsException; +import org.apache.struts2.ognl.StrutsContext; import java.beans.IntrospectionException; import java.beans.PropertyDescriptor; @@ -64,7 +64,7 @@ public class CompoundRootAccessor implements RootAccessor, InternalDestroyable { * Used by OGNl to generate bytecode */ @Override - public String getSourceAccessor(OgnlContext context, Object target, Object index) { + public String getSourceAccessor(StrutsContext context, Object target, Object index) { return null; } @@ -72,7 +72,7 @@ public String getSourceAccessor(OgnlContext context, Object target, Object index * Used by OGNl to generate bytecode */ @Override - public String getSourceSetter(OgnlContext context, Object target, Object index) { + public String getSourceSetter(StrutsContext context, Object target, Object index) { return null; } @@ -96,7 +96,7 @@ public void useDisallowCustomOgnlMap(String disallowCustomOgnlMap) { } @Override - public void setProperty(OgnlContext context, Object target, Object name, Object value) throws OgnlException { + public void setProperty(StrutsContext context, Object target, Object name, Object value) throws OgnlException { CompoundRoot root = (CompoundRoot) target; for (Object o : root) { @@ -138,7 +138,7 @@ public void setProperty(OgnlContext context, Object target, Object name, Object } @Override - public Object getProperty(OgnlContext context, Object target, Object name) throws OgnlException { + public Object getProperty(StrutsContext context, Object target, Object name) throws OgnlException { CompoundRoot root = (CompoundRoot) target; if (name instanceof Integer index) { @@ -182,7 +182,7 @@ public Object getProperty(OgnlContext context, Object target, Object name) throw } @Override - public Object callMethod(OgnlContext context, Object target, String name, Object[] objects) throws MethodFailedException { + public Object callMethod(StrutsContext context, Object target, String name, Object[] objects) throws MethodFailedException { CompoundRoot root = (CompoundRoot) target; if ("describe".equals(name)) { @@ -270,12 +270,12 @@ public Object callMethod(OgnlContext context, Object target, String name, Object } @Override - public Object callStaticMethod(OgnlContext transientVars, Class aClass, String s, Object[] objects) throws MethodFailedException { + public Object callStaticMethod(StrutsContext transientVars, Class aClass, String s, Object[] objects) throws MethodFailedException { return null; } @Override - public Class classForName(String className, OgnlContext context) throws ClassNotFoundException { + public Class classForName(String className, StrutsContext context) throws ClassNotFoundException { Object root = Ognl.getRoot(context); if (disallowCustomOgnlMap) { diff --git a/core/src/main/java/org/apache/struts2/ognl/accessor/HttpParametersPropertyAccessor.java b/core/src/main/java/org/apache/struts2/ognl/accessor/HttpParametersPropertyAccessor.java index 53191030cc..1a092325c0 100644 --- a/core/src/main/java/org/apache/struts2/ognl/accessor/HttpParametersPropertyAccessor.java +++ b/core/src/main/java/org/apache/struts2/ognl/accessor/HttpParametersPropertyAccessor.java @@ -19,20 +19,20 @@ package org.apache.struts2.ognl.accessor; import ognl.ObjectPropertyAccessor; -import ognl.OgnlContext; import ognl.OgnlException; import org.apache.struts2.dispatcher.HttpParameters; +import org.apache.struts2.ognl.StrutsContext; -public class HttpParametersPropertyAccessor extends ObjectPropertyAccessor { +public class HttpParametersPropertyAccessor extends ObjectPropertyAccessor { @Override - public Object getProperty(OgnlContext context, Object target, Object oname) throws OgnlException { + public Object getProperty(StrutsContext context, Object target, Object oname) throws OgnlException { HttpParameters parameters = (HttpParameters) target; return parameters.get(String.valueOf(oname)).getObject(); } @Override - public void setProperty(OgnlContext context, Object target, Object oname, Object value) throws OgnlException { + public void setProperty(StrutsContext context, Object target, Object oname, Object value) throws OgnlException { throw new OgnlException("Access to " + target.getClass().getName() + " is read-only!"); } } \ No newline at end of file diff --git a/core/src/main/java/org/apache/struts2/ognl/accessor/ObjectAccessor.java b/core/src/main/java/org/apache/struts2/ognl/accessor/ObjectAccessor.java index 20973b577b..513cb9f488 100644 --- a/core/src/main/java/org/apache/struts2/ognl/accessor/ObjectAccessor.java +++ b/core/src/main/java/org/apache/struts2/ognl/accessor/ObjectAccessor.java @@ -21,12 +21,12 @@ import org.apache.struts2.conversion.impl.XWorkConverter; import org.apache.struts2.util.reflection.ReflectionContextState; import ognl.ObjectPropertyAccessor; -import ognl.OgnlContext; import ognl.OgnlException; +import org.apache.struts2.ognl.StrutsContext; -public class ObjectAccessor extends ObjectPropertyAccessor { +public class ObjectAccessor extends ObjectPropertyAccessor { @Override - public Object getProperty(OgnlContext map, Object o, Object o1) throws OgnlException { + public Object getProperty(StrutsContext map, Object o, Object o1) throws OgnlException { Object obj = super.getProperty(map, o, o1); map.put(XWorkConverter.LAST_BEAN_CLASS_ACCESSED, o.getClass()); diff --git a/core/src/main/java/org/apache/struts2/ognl/accessor/ObjectProxyPropertyAccessor.java b/core/src/main/java/org/apache/struts2/ognl/accessor/ObjectProxyPropertyAccessor.java index a8aec73053..3120588a64 100644 --- a/core/src/main/java/org/apache/struts2/ognl/accessor/ObjectProxyPropertyAccessor.java +++ b/core/src/main/java/org/apache/struts2/ognl/accessor/ObjectProxyPropertyAccessor.java @@ -20,10 +20,10 @@ import org.apache.struts2.ognl.ObjectProxy; import org.apache.struts2.util.reflection.ReflectionContextState; -import ognl.OgnlContext; import ognl.OgnlException; import ognl.OgnlRuntime; import ognl.PropertyAccessor; +import org.apache.struts2.ognl.StrutsContext; /** * Is able to access (set/get) properties on a given object. @@ -33,13 +33,13 @@ * * @author Gabe */ -public class ObjectProxyPropertyAccessor implements PropertyAccessor { +public class ObjectProxyPropertyAccessor implements PropertyAccessor { /** * Used by OGNl to generate bytecode */ @Override - public String getSourceAccessor(OgnlContext context, Object target, Object index) { + public String getSourceAccessor(StrutsContext context, Object target, Object index) { return null; //To change body of implemented methods use File | Settings | File Templates. } @@ -47,25 +47,27 @@ public String getSourceAccessor(OgnlContext context, Object target, Object index * Used by OGNl to generate bytecode */ @Override - public String getSourceSetter(OgnlContext context, Object target, Object index) { + public String getSourceSetter(StrutsContext context, Object target, Object index) { return null; } @Override - public Object getProperty(OgnlContext context, Object target, Object name) throws OgnlException { + @SuppressWarnings({"unchecked", "rawtypes"}) + public Object getProperty(StrutsContext context, Object target, Object name) throws OgnlException { ObjectProxy proxy = (ObjectProxy) target; setupContext(context, proxy); - return OgnlRuntime.getPropertyAccessor(proxy.getValue().getClass()).getProperty(context, target, name); + return ((PropertyAccessor) OgnlRuntime.getPropertyAccessor(proxy.getValue().getClass())).getProperty(context, target, name); } @Override - public void setProperty(OgnlContext context, Object target, Object name, Object value) throws OgnlException { + @SuppressWarnings({"unchecked", "rawtypes"}) + public void setProperty(StrutsContext context, Object target, Object name, Object value) throws OgnlException { ObjectProxy proxy = (ObjectProxy) target; setupContext(context, proxy); - OgnlRuntime.getPropertyAccessor(proxy.getValue().getClass()).setProperty(context, target, name, value); + ((PropertyAccessor) OgnlRuntime.getPropertyAccessor(proxy.getValue().getClass())).setProperty(context, target, name, value); } /** @@ -75,7 +77,7 @@ public void setProperty(OgnlContext context, Object target, Object name, Object * @param context * @param proxy */ - private void setupContext(OgnlContext context, ObjectProxy proxy) { + private void setupContext(StrutsContext context, ObjectProxy proxy) { ReflectionContextState.setLastBeanClassAccessed(context, proxy.getLastClassAccessed()); ReflectionContextState.setLastBeanPropertyAccessed(context, proxy.getLastPropertyAccessed()); } diff --git a/core/src/main/java/org/apache/struts2/ognl/accessor/ParameterPropertyAccessor.java b/core/src/main/java/org/apache/struts2/ognl/accessor/ParameterPropertyAccessor.java index cb402304ab..2745b779cc 100644 --- a/core/src/main/java/org/apache/struts2/ognl/accessor/ParameterPropertyAccessor.java +++ b/core/src/main/java/org/apache/struts2/ognl/accessor/ParameterPropertyAccessor.java @@ -19,14 +19,14 @@ package org.apache.struts2.ognl.accessor; import ognl.ObjectPropertyAccessor; -import ognl.OgnlContext; import ognl.OgnlException; import org.apache.struts2.dispatcher.Parameter; +import org.apache.struts2.ognl.StrutsContext; -public class ParameterPropertyAccessor extends ObjectPropertyAccessor { +public class ParameterPropertyAccessor extends ObjectPropertyAccessor { @Override - public Object getProperty(OgnlContext context, Object target, Object oname) throws OgnlException { + public Object getProperty(StrutsContext context, Object target, Object oname) throws OgnlException { if (target instanceof Parameter parameter) { if ("value".equalsIgnoreCase(String.valueOf(oname))) { throw new OgnlException("Access to " + oname + " is not allowed! Call parameter name directly!"); @@ -37,7 +37,7 @@ public Object getProperty(OgnlContext context, Object target, Object oname) thro } @Override - public void setProperty(OgnlContext context, Object target, Object oname, Object value) throws OgnlException { + public void setProperty(StrutsContext context, Object target, Object oname, Object value) throws OgnlException { if (target instanceof Parameter) { throw new OgnlException("Access to " + target.getClass().getName() + " is read-only!"); } else { diff --git a/core/src/main/java/org/apache/struts2/ognl/accessor/RootAccessor.java b/core/src/main/java/org/apache/struts2/ognl/accessor/RootAccessor.java index 50e9feea00..febfc70124 100644 --- a/core/src/main/java/org/apache/struts2/ognl/accessor/RootAccessor.java +++ b/core/src/main/java/org/apache/struts2/ognl/accessor/RootAccessor.java @@ -21,9 +21,10 @@ import ognl.ClassResolver; import ognl.MethodAccessor; import ognl.PropertyAccessor; +import org.apache.struts2.ognl.StrutsContext; /** * @since 6.4.0 */ -public interface RootAccessor extends PropertyAccessor, MethodAccessor, ClassResolver { +public interface RootAccessor extends PropertyAccessor, MethodAccessor, ClassResolver { } diff --git a/core/src/main/java/org/apache/struts2/ognl/accessor/XWorkCollectionPropertyAccessor.java b/core/src/main/java/org/apache/struts2/ognl/accessor/XWorkCollectionPropertyAccessor.java index d9979b8f55..07460a3f29 100644 --- a/core/src/main/java/org/apache/struts2/ognl/accessor/XWorkCollectionPropertyAccessor.java +++ b/core/src/main/java/org/apache/struts2/ognl/accessor/XWorkCollectionPropertyAccessor.java @@ -25,10 +25,10 @@ import org.apache.struts2.ognl.OgnlUtil; import org.apache.struts2.util.reflection.ReflectionContextState; import ognl.ObjectPropertyAccessor; -import ognl.OgnlContext; import ognl.OgnlException; import ognl.OgnlRuntime; import ognl.SetPropertyAccessor; +import org.apache.struts2.ognl.StrutsContext; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -40,7 +40,7 @@ /** * @author Gabe */ -public class XWorkCollectionPropertyAccessor extends SetPropertyAccessor { +public class XWorkCollectionPropertyAccessor extends SetPropertyAccessor { private static final Logger LOG = LogManager.getLogger(XWorkCollectionPropertyAccessor.class); @@ -87,7 +87,7 @@ public void setOgnlUtil(OgnlUtil util) { * @see ognl.PropertyAccessor#getProperty(java.util.Map, Object, Object) */ @Override - public Object getProperty(OgnlContext context, Object target, Object key) throws OgnlException { + public Object getProperty(StrutsContext context, Object target, Object key) throws OgnlException { LOG.trace("Entering getProperty()"); //check if it is a generic type property. @@ -186,7 +186,7 @@ public Object getProperty(OgnlContext context, Object target, Object key) throws * Gets an indexed Map by a given key property with the key being * the value of the property and the value being the */ - private Map getSetMap(OgnlContext context, Collection collection, String property) throws OgnlException { + private Map getSetMap(StrutsContext context, Collection collection, String property) throws OgnlException { LOG.trace("getting set Map"); String path = ReflectionContextState.getCurrentPropertyPath(context); @@ -211,7 +211,7 @@ private Map getSetMap(OgnlContext context, Collection collection, String propert /* * gets a bean with the given */ - public Object getPropertyThroughIteration(OgnlContext context, Collection collection, String property, Object key) + public Object getPropertyThroughIteration(StrutsContext context, Collection collection, String property, Object key) throws OgnlException { //TODO for (Object currTest : collection) { @@ -224,7 +224,7 @@ public Object getPropertyThroughIteration(OgnlContext context, Collection collec } @Override - public void setProperty(OgnlContext context, Object target, Object name, Object value) throws OgnlException { + public void setProperty(StrutsContext context, Object target, Object name, Object value) throws OgnlException { Class lastClass = (Class) context.get(XWorkConverter.LAST_BEAN_CLASS_ACCESSED); String lastProperty = (String) context.get(XWorkConverter.LAST_BEAN_PROPERTY_ACCESSED); Class convertToClass = objectTypeDeterminer.getElementClass(lastClass, lastProperty, name); @@ -256,7 +256,7 @@ public void setProperty(OgnlContext context, Object target, Object name, Object super.setProperty(context, target, name, realValue); } - private Object getRealValue(OgnlContext context, Object value, Class convertToClass) { + private Object getRealValue(StrutsContext context, Object value, Class convertToClass) { if (value == null || convertToClass == null) { return value; } diff --git a/core/src/main/java/org/apache/struts2/ognl/accessor/XWorkEnumerationAccessor.java b/core/src/main/java/org/apache/struts2/ognl/accessor/XWorkEnumerationAccessor.java index df54e49b88..780f27903e 100644 --- a/core/src/main/java/org/apache/struts2/ognl/accessor/XWorkEnumerationAccessor.java +++ b/core/src/main/java/org/apache/struts2/ognl/accessor/XWorkEnumerationAccessor.java @@ -20,15 +20,15 @@ import ognl.EnumerationPropertyAccessor; import ognl.ObjectPropertyAccessor; -import ognl.OgnlContext; import ognl.OgnlException; +import org.apache.struts2.ognl.StrutsContext; -public class XWorkEnumerationAccessor extends EnumerationPropertyAccessor { +public class XWorkEnumerationAccessor extends EnumerationPropertyAccessor { - private final ObjectPropertyAccessor opa = new ObjectPropertyAccessor(); + private final ObjectPropertyAccessor opa = new ObjectPropertyAccessor<>(); @Override - public void setProperty(OgnlContext context, Object target, Object name, Object value) throws OgnlException { + public void setProperty(StrutsContext context, Object target, Object name, Object value) throws OgnlException { opa.setProperty(context, target, name, value); } } diff --git a/core/src/main/java/org/apache/struts2/ognl/accessor/XWorkIteratorPropertyAccessor.java b/core/src/main/java/org/apache/struts2/ognl/accessor/XWorkIteratorPropertyAccessor.java index daa17740e6..9884dba017 100644 --- a/core/src/main/java/org/apache/struts2/ognl/accessor/XWorkIteratorPropertyAccessor.java +++ b/core/src/main/java/org/apache/struts2/ognl/accessor/XWorkIteratorPropertyAccessor.java @@ -20,15 +20,15 @@ import ognl.IteratorPropertyAccessor; import ognl.ObjectPropertyAccessor; -import ognl.OgnlContext; import ognl.OgnlException; +import org.apache.struts2.ognl.StrutsContext; -public class XWorkIteratorPropertyAccessor extends IteratorPropertyAccessor { +public class XWorkIteratorPropertyAccessor extends IteratorPropertyAccessor { - private final ObjectPropertyAccessor opa = new ObjectPropertyAccessor(); + private final ObjectPropertyAccessor opa = new ObjectPropertyAccessor<>(); @Override - public void setProperty(OgnlContext context, Object target, Object name, Object value) throws OgnlException { + public void setProperty(StrutsContext context, Object target, Object name, Object value) throws OgnlException { opa.setProperty(context, target, name, value); } } diff --git a/core/src/main/java/org/apache/struts2/ognl/accessor/XWorkListPropertyAccessor.java b/core/src/main/java/org/apache/struts2/ognl/accessor/XWorkListPropertyAccessor.java index e741877cb0..31d70c6ff5 100644 --- a/core/src/main/java/org/apache/struts2/ognl/accessor/XWorkListPropertyAccessor.java +++ b/core/src/main/java/org/apache/struts2/ognl/accessor/XWorkListPropertyAccessor.java @@ -25,9 +25,9 @@ import org.apache.struts2.ognl.OgnlUtil; import org.apache.struts2.util.reflection.ReflectionContextState; import ognl.ListPropertyAccessor; -import ognl.OgnlContext; import ognl.OgnlException; import ognl.PropertyAccessor; +import org.apache.struts2.ognl.StrutsContext; import org.apache.struts2.StrutsConstants; import org.apache.struts2.StrutsException; @@ -41,7 +41,7 @@ * * @author Gabriel Zimmerman */ -public class XWorkListPropertyAccessor extends ListPropertyAccessor { +public class XWorkListPropertyAccessor extends ListPropertyAccessor { private XWorkCollectionPropertyAccessor _sAcc = new XWorkCollectionPropertyAccessor(); @@ -57,7 +57,7 @@ public void setAutoGrowCollectionLimit(String value) { } @Inject("java.util.Collection") - public void setXWorkCollectionPropertyAccessor(PropertyAccessor acc) { + public void setXWorkCollectionPropertyAccessor(PropertyAccessor acc) { this._sAcc = (XWorkCollectionPropertyAccessor) acc; } @@ -82,7 +82,7 @@ public void setOgnlUtil(OgnlUtil util) { } @Override - public Object getProperty(OgnlContext context, Object target, Object name) throws OgnlException { + public Object getProperty(StrutsContext context, Object target, Object name) throws OgnlException { if (ReflectionContextState.isGettingByKeyProperty(context) || name.equals(XWorkCollectionPropertyAccessor.KEY_PROPERTY_FOR_CREATION)) { @@ -137,7 +137,7 @@ public Object getProperty(OgnlContext context, Object target, Object name) throw } @Override - public void setProperty(OgnlContext context, Object target, Object name, Object value) + public void setProperty(StrutsContext context, Object target, Object name, Object value) throws OgnlException { Class lastClass = (Class) context.get(XWorkConverter.LAST_BEAN_CLASS_ACCESSED); @@ -185,7 +185,7 @@ public void setProperty(OgnlContext context, Object target, Object name, Object super.setProperty(context, target, name, realValue); } - private Object getRealValue(OgnlContext context, Object value, Class convertToClass) { + private Object getRealValue(StrutsContext context, Object value, Class convertToClass) { if (value == null || convertToClass == null) { return value; } diff --git a/core/src/main/java/org/apache/struts2/ognl/accessor/XWorkMapPropertyAccessor.java b/core/src/main/java/org/apache/struts2/ognl/accessor/XWorkMapPropertyAccessor.java index f15223fdf9..70adb314bf 100644 --- a/core/src/main/java/org/apache/struts2/ognl/accessor/XWorkMapPropertyAccessor.java +++ b/core/src/main/java/org/apache/struts2/ognl/accessor/XWorkMapPropertyAccessor.java @@ -24,8 +24,8 @@ import org.apache.struts2.inject.Inject; import org.apache.struts2.util.reflection.ReflectionContextState; import ognl.MapPropertyAccessor; -import ognl.OgnlContext; import ognl.OgnlException; +import org.apache.struts2.ognl.StrutsContext; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -37,7 +37,7 @@ * * @author Gabriel Zimmerman */ -public class XWorkMapPropertyAccessor extends MapPropertyAccessor { +public class XWorkMapPropertyAccessor extends MapPropertyAccessor { private static final Logger LOG = LogManager.getLogger(XWorkMapPropertyAccessor.class); @@ -63,7 +63,7 @@ public void setObjectTypeDeterminer(ObjectTypeDeterminer ot) { } @Override - public Object getProperty(OgnlContext context, Object target, Object name) throws OgnlException { + public Object getProperty(StrutsContext context, Object target, Object name) throws OgnlException { LOG.trace("Entering getProperty ({},{},{})", context, target, name); ReflectionContextState.updateCurrentPropertyPath(context, name); @@ -123,7 +123,7 @@ private boolean contains(String[] array, String name) { } @Override - public void setProperty(OgnlContext context, Object target, Object name, Object value) throws OgnlException { + public void setProperty(StrutsContext context, Object target, Object name, Object value) throws OgnlException { LOG.trace("Entering setProperty({},{},{},{})", context, target, name, value); Object key = getKey(context, name); @@ -131,7 +131,7 @@ public void setProperty(OgnlContext context, Object target, Object name, Object map.put(key, getValue(context, value)); } - private Object getValue(OgnlContext context, Object value) { + private Object getValue(StrutsContext context, Object value) { Class lastClass = (Class) context.get(XWorkConverter.LAST_BEAN_CLASS_ACCESSED); String lastProperty = (String) context.get(XWorkConverter.LAST_BEAN_PROPERTY_ACCESSED); if (lastClass == null || lastProperty == null) { @@ -144,7 +144,7 @@ private Object getValue(OgnlContext context, Object value) { return xworkConverter.convertValue(context, value, elementClass); } - private Object getKey(OgnlContext context, Object name) { + private Object getKey(StrutsContext context, Object name) { Class lastClass = (Class) context.get(XWorkConverter.LAST_BEAN_CLASS_ACCESSED); String lastProperty = (String) context.get(XWorkConverter.LAST_BEAN_PROPERTY_ACCESSED); if (lastClass == null || lastProperty == null) { diff --git a/core/src/main/java/org/apache/struts2/ognl/accessor/XWorkMethodAccessor.java b/core/src/main/java/org/apache/struts2/ognl/accessor/XWorkMethodAccessor.java index 025553997d..2bc035c30e 100644 --- a/core/src/main/java/org/apache/struts2/ognl/accessor/XWorkMethodAccessor.java +++ b/core/src/main/java/org/apache/struts2/ognl/accessor/XWorkMethodAccessor.java @@ -21,9 +21,9 @@ import org.apache.struts2.util.reflection.ReflectionContextState; import ognl.MethodFailedException; import ognl.ObjectMethodAccessor; -import ognl.OgnlContext; import ognl.OgnlRuntime; import ognl.PropertyAccessor; +import org.apache.struts2.ognl.StrutsContext; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -38,12 +38,13 @@ * @author Patrick Lightbody * @author tmjee */ -public class XWorkMethodAccessor extends ObjectMethodAccessor { +public class XWorkMethodAccessor extends ObjectMethodAccessor { private static final Logger LOG = LogManager.getLogger(XWorkMethodAccessor.class); @Override - public Object callMethod(OgnlContext context, Object object, String string, Object[] objects) throws MethodFailedException { + @SuppressWarnings("unchecked") + public Object callMethod(StrutsContext context, Object object, String string, Object[] objects) throws MethodFailedException { //Collection property accessing //this if statement ensures that ognl @@ -94,7 +95,7 @@ public Object callMethod(OgnlContext context, Object object, String string, Obje } } - private Object callMethodWithDebugInfo(OgnlContext context, Object object, String methodName, Object[] objects) throws MethodFailedException { + private Object callMethodWithDebugInfo(StrutsContext context, Object object, String methodName, Object[] objects) throws MethodFailedException { try { return super.callMethod(context, object, methodName, objects); } catch (MethodFailedException e) { @@ -109,7 +110,7 @@ private Object callMethodWithDebugInfo(OgnlContext context, Object object, Strin } @Override - public Object callStaticMethod(OgnlContext context, Class aClass, String string, Object[] objects) throws MethodFailedException { + public Object callStaticMethod(StrutsContext context, Class aClass, String string, Object[] objects) throws MethodFailedException { boolean e = ReflectionContextState.isDenyMethodExecution(context); if (!e) { @@ -119,7 +120,7 @@ public Object callStaticMethod(OgnlContext context, Class aClass, String string, } } - private Object callStaticMethodWithDebugInfo(OgnlContext context, Class aClass, String methodName, + private Object callStaticMethodWithDebugInfo(StrutsContext context, Class aClass, String methodName, Object[] objects) throws MethodFailedException { try { return super.callStaticMethod(context, aClass, methodName, objects); diff --git a/core/src/main/java/org/apache/struts2/ognl/accessor/XWorkObjectPropertyAccessor.java b/core/src/main/java/org/apache/struts2/ognl/accessor/XWorkObjectPropertyAccessor.java index c518d42cca..2140524870 100644 --- a/core/src/main/java/org/apache/struts2/ognl/accessor/XWorkObjectPropertyAccessor.java +++ b/core/src/main/java/org/apache/struts2/ognl/accessor/XWorkObjectPropertyAccessor.java @@ -21,15 +21,15 @@ import org.apache.struts2.conversion.impl.XWorkConverter; import org.apache.struts2.util.reflection.ReflectionContextState; import ognl.ObjectPropertyAccessor; -import ognl.OgnlContext; import ognl.OgnlException; +import org.apache.struts2.ognl.StrutsContext; /** * @author Gabe */ -public class XWorkObjectPropertyAccessor extends ObjectPropertyAccessor { +public class XWorkObjectPropertyAccessor extends ObjectPropertyAccessor { @Override - public Object getProperty(OgnlContext context, Object target, Object oname) throws OgnlException { + public Object getProperty(StrutsContext context, Object target, Object oname) throws OgnlException { //set the last set objects in the context //so if the next objects accessed are //Maps or Collections they can use the information diff --git a/core/src/test/java/org/apache/struts2/interceptor/parameter/ParametersInterceptorTest.java b/core/src/test/java/org/apache/struts2/interceptor/parameter/ParametersInterceptorTest.java index ba2f48969d..dcf022799e 100644 --- a/core/src/test/java/org/apache/struts2/interceptor/parameter/ParametersInterceptorTest.java +++ b/core/src/test/java/org/apache/struts2/interceptor/parameter/ParametersInterceptorTest.java @@ -42,7 +42,7 @@ import org.apache.struts2.util.ValueStack; import org.apache.struts2.util.ValueStackFactory; import org.apache.struts2.util.reflection.ReflectionContextState; -import ognl.OgnlContext; +import org.apache.struts2.ognl.StrutsContext; import org.apache.struts2.action.NoParameters; import org.apache.struts2.action.ParameterNameAware; import org.apache.struts2.action.ParameterValueAware; @@ -353,7 +353,7 @@ public void testAccessToOgnlInternals() throws Exception { //then assertEquals("This is blah", ((SimpleAction) proxy.getAction()).getBlah()); Field field = ReflectionContextState.class.getField("DENY_METHOD_EXECUTION"); - boolean allowStaticFieldAccess = ((OgnlContext) stack.getContext()).getMemberAccess().isAccessible((OgnlContext) stack.getContext(), ReflectionContextState.class, field, ""); + boolean allowStaticFieldAccess = ((StrutsContext) stack.getContext()).getMemberAccess().isAccessible((StrutsContext) stack.getContext(), ReflectionContextState.class, field, ""); assertFalse(allowStaticFieldAccess); } diff --git a/core/src/test/java/org/apache/struts2/ognl/OgnlUtilTest.java b/core/src/test/java/org/apache/struts2/ognl/OgnlUtilTest.java index 4361331c4d..bc0ab5e691 100644 --- a/core/src/test/java/org/apache/struts2/ognl/OgnlUtilTest.java +++ b/core/src/test/java/org/apache/struts2/ognl/OgnlUtilTest.java @@ -23,7 +23,6 @@ import ognl.NoSuchPropertyException; import ognl.NullHandler; import ognl.Ognl; -import ognl.OgnlContext; import ognl.OgnlException; import ognl.OgnlRuntime; import ognl.SimpleNode; @@ -90,12 +89,12 @@ private void resetOgnlUtil(Map properties) { public void testCanSetADependentObject() { String dogName = "fido"; - OgnlRuntime.setNullHandler(Owner.class, new NullHandler() { - public Object nullMethodResult(OgnlContext context, Object o, String s, Object[] objects) { + OgnlRuntime.setNullHandler(Owner.class, new NullHandler() { + public Object nullMethodResult(StrutsContext context, Object o, String s, Object[] objects) { return null; } - public Object nullPropertyValue(OgnlContext context, Object o, Object o1) { + public Object nullPropertyValue(StrutsContext context, Object o, Object o1) { String methodName = o1.toString(); String getter = "set" + methodName.substring(0, 1).toUpperCase() + methodName.substring(1); Method[] methods = o.getClass().getDeclaredMethods(); @@ -199,7 +198,7 @@ public void testLRUCacheEnabledMaxSize() throws OgnlException { public void testExpressionIsCachedIrrespectiveOfItsExecutionStatus() { Foo foo = new Foo(); - OgnlContext context = ognlUtil.createDefaultContext(foo); + StrutsContext context = ognlUtil.createDefaultContext(foo); // Expression which executes with success try { @@ -223,7 +222,7 @@ public void testExpressionIsLRUCachedIrrespectiveOfItsExecutionStatus() { ognlUtil.setContainer(container); // Must be explicitly set as the generated OgnlUtil instance has no container ognlUtil.setEnableExpressionCache("true"); Foo foo = new Foo(); - OgnlContext context = ognlUtil.createDefaultContext(foo); + StrutsContext context = ognlUtil.createDefaultContext(foo); // Expression which executes with success try { @@ -243,7 +242,7 @@ public void testExpressionIsLRUCachedIrrespectiveOfItsExecutionStatus() { public void testMethodExpressionIsCachedIrrespectiveOfItsExecutionStatus() { Foo foo = new Foo(); - OgnlContext context = ognlUtil.createDefaultContext(foo); + StrutsContext context = ognlUtil.createDefaultContext(foo); // Method expression which executes with success try { @@ -846,7 +845,7 @@ public void testSetList() throws Exception { ChainingInterceptor foo = new ChainingInterceptor(); ChainingInterceptor foo2 = new ChainingInterceptor(); - OgnlContext context = ognlUtil.createDefaultContext(null); + StrutsContext context = ognlUtil.createDefaultContext(null); SimpleNode expression = (SimpleNode) Ognl.parseExpression("{'a','ruby','b','tom'}"); Ognl.getValue(expression, context, "aksdj"); @@ -903,7 +902,7 @@ public void testStringToLong() { public void testBeanMapExpressions() throws OgnlException, NoSuchMethodException { Foo foo = new Foo(); - OgnlContext context = ognlUtil.createDefaultContext(foo); + StrutsContext context = ognlUtil.createDefaultContext(foo); SecurityMemberAccess sma = (SecurityMemberAccess) context.getMemberAccess(); sma.useExcludedPackageNames("org.apache.struts2.ognl"); diff --git a/core/src/test/java/org/apache/struts2/ognl/SecurityMemberAccessTest.java b/core/src/test/java/org/apache/struts2/ognl/SecurityMemberAccessTest.java index a9b7b8c12d..bcd62e3aeb 100644 --- a/core/src/test/java/org/apache/struts2/ognl/SecurityMemberAccessTest.java +++ b/core/src/test/java/org/apache/struts2/ognl/SecurityMemberAccessTest.java @@ -19,7 +19,6 @@ package org.apache.struts2.ognl; import ognl.MemberAccess; -import ognl.OgnlContext; import org.apache.commons.lang3.reflect.FieldUtils; import org.apache.struts2.TestBean; import org.apache.struts2.config.ConfigurationException; @@ -55,7 +54,7 @@ public class SecurityMemberAccessTest { - private OgnlContext context; + private StrutsContext context; private FooBar target; protected SecurityMemberAccess sma; protected ProviderAllowlist mockedProviderAllowlist; @@ -64,12 +63,12 @@ public class SecurityMemberAccessTest { @Before public void setUp() { - context = ognl.Ognl.createDefaultContext(null); target = new FooBar(); mockedProviderAllowlist = mock(ProviderAllowlist.class); mockedThreadAllowlist = mock(ThreadAllowlist.class); proxyService = new StrutsProxyService(new StrutsProxyCacheFactory<>("1000", "basic")); assignNewSma(true); + context = new StrutsContext(sma); } protected void assignNewSma(boolean allowStaticFieldAccess) { diff --git a/core/src/test/java/org/apache/struts2/ognl/SetPropertiesTest.java b/core/src/test/java/org/apache/struts2/ognl/SetPropertiesTest.java index db928acb54..49f9d75392 100644 --- a/core/src/test/java/org/apache/struts2/ognl/SetPropertiesTest.java +++ b/core/src/test/java/org/apache/struts2/ognl/SetPropertiesTest.java @@ -37,7 +37,6 @@ import org.apache.struts2.util.location.LocatableProperties; import org.apache.struts2.util.reflection.ReflectionContextState; import ognl.Ognl; -import ognl.OgnlContext; import java.util.ArrayList; import java.util.Collection; @@ -57,7 +56,8 @@ public void setUp() throws Exception { public void testOgnlUtilEmptyStringAsLong() { Bar bar = new Bar(); - OgnlContext context = Ognl.createDefaultContext(bar, new SecurityMemberAccess(null, null)); + StrutsContext context = new StrutsContext(new SecurityMemberAccess(null, null)); + context.withRoot(bar); context.put(XWorkConverter.REPORT_CONVERSION_ERRORS, Boolean.TRUE); bar.setId(null); @@ -81,7 +81,7 @@ public void testSetCollectionByConverterFromArray() { ValueStack vs = ActionContext.getContext().getValueStack(); vs.getContext().put(XWorkConverter.REPORT_CONVERSION_ERRORS, Boolean.TRUE); - XWorkConverter c = (XWorkConverter) ((OgnlTypeConverterWrapper) Ognl.getTypeConverter((OgnlContext) vs.getContext())).getTarget(); + XWorkConverter c = (XWorkConverter) ((OgnlTypeConverterWrapper) ((StrutsContext) vs.getContext()).getTypeConverter()).getTarget(); c.registerConverter(Cat.class.getName(), new FooBarConverter()); vs.push(foo); @@ -97,7 +97,7 @@ public void testSetCollectionByConverterFromCollection() { ValueStack vs = ActionContext.getContext().getValueStack(); vs.getContext().put(XWorkConverter.REPORT_CONVERSION_ERRORS, Boolean.TRUE); - XWorkConverter c = (XWorkConverter) ((OgnlTypeConverterWrapper) Ognl.getTypeConverter((OgnlContext) vs.getContext())).getTarget(); + XWorkConverter c = (XWorkConverter) ((OgnlTypeConverterWrapper) ((StrutsContext) vs.getContext()).getTypeConverter()).getTarget(); c.registerConverter(Cat.class.getName(), new FooBarConverter()); vs.push(foo); diff --git a/core/src/test/java/org/apache/struts2/ognl/StrutsContextTest.java b/core/src/test/java/org/apache/struts2/ognl/StrutsContextTest.java new file mode 100644 index 0000000000..309362a135 --- /dev/null +++ b/core/src/test/java/org/apache/struts2/ognl/StrutsContextTest.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.struts2.ognl; + +import ognl.ClassResolver; +import ognl.MemberAccess; +import ognl.TypeConverter; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +@SuppressWarnings("unchecked") +public class StrutsContextTest { + + @Test + public void shouldCreateContextWithRequiredMemberAccess() { + MemberAccess memberAccess = mock(MemberAccess.class); + var context = new StrutsContext(memberAccess); + + assertThat(context).isNotNull(); + assertThat(context.getMemberAccess()).isSameAs(memberAccess); + } + + @Test + public void shouldCreateContextWithAllComponents() { + MemberAccess memberAccess = mock(MemberAccess.class); + ClassResolver classResolver = mock(ClassResolver.class); + TypeConverter typeConverter = mock(TypeConverter.class); + + var context = new StrutsContext(memberAccess, classResolver, typeConverter); + + assertThat(context.getMemberAccess()).isSameAs(memberAccess); + assertThat(context.getClassResolver()).isSameAs(classResolver); + assertThat(context.getTypeConverter()).isSameAs(typeConverter); + } + + @Test + public void shouldSupportRootObject() { + MemberAccess memberAccess = mock(MemberAccess.class); + var root = new Object(); + var context = new StrutsContext(memberAccess); + context.withRoot(root); + + assertThat(context.getRoot()).isSameAs(root); + } + + @Test + public void shouldImplementMapInterface() { + MemberAccess memberAccess = mock(MemberAccess.class); + var context = new StrutsContext(memberAccess); + + context.put("testKey", "testValue"); + assertThat(context.get("testKey")).isEqualTo("testValue"); + } +} diff --git a/core/src/test/java/org/apache/struts2/util/SecurityMemberAccessInServletsTest.java b/core/src/test/java/org/apache/struts2/util/SecurityMemberAccessInServletsTest.java index 8c94227339..d66ca88788 100644 --- a/core/src/test/java/org/apache/struts2/util/SecurityMemberAccessInServletsTest.java +++ b/core/src/test/java/org/apache/struts2/util/SecurityMemberAccessInServletsTest.java @@ -19,8 +19,8 @@ package org.apache.struts2.util; import org.apache.struts2.ognl.SecurityMemberAccess; +import org.apache.struts2.ognl.StrutsContext; import jakarta.servlet.jsp.tagext.TagSupport; -import ognl.OgnlContext; import org.apache.struts2.StrutsInternalTestCase; import org.apache.struts2.views.jsp.ActionTag; @@ -28,12 +28,12 @@ public class SecurityMemberAccessInServletsTest extends StrutsInternalTestCase { - private OgnlContext context; + private StrutsContext context; @Override public void setUp() throws Exception { super.setUp(); - context = ognl.Ognl.createDefaultContext(null); + context = new StrutsContext(new SecurityMemberAccess(null, null)); } public void testJavaxServletPackageAccess() throws Exception { diff --git a/docs/superpowers/plans/2026-04-04-hibernate-proxy-detection-optimization.md b/docs/superpowers/plans/2026-04-04-hibernate-proxy-detection-optimization.md new file mode 100644 index 0000000000..cdc82a9997 --- /dev/null +++ b/docs/superpowers/plans/2026-04-04-hibernate-proxy-detection-optimization.md @@ -0,0 +1,272 @@ +# Hibernate Proxy Detection Optimization + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Eliminate `LinkageError` exceptions thrown when Hibernate is not on the classpath by detecting availability once at class-load time. + +**Architecture:** Add a static availability check in `StrutsProxyService` that probes for `org.hibernate.proxy.HibernateProxy` once during class initialization. All Hibernate-related methods short-circuit immediately when Hibernate is absent. Same pattern applied to deprecated `ProxyUtil`. + +**Tech Stack:** Java 17, JUnit 5, AssertJ, Mockito + +--- + +### Task 1: Add Hibernate Availability Check to StrutsProxyService + +**Files:** +- Modify: `core/src/main/java/org/apache/struts2/util/StrutsProxyService.java` +- Test: `core/src/test/java/org/apache/struts2/util/StrutsProxyServiceTest.java` + +- [ ] **Step 1: Write the failing test — verify no LinkageError is thrown when Hibernate classes are used** + +The existing tests already call `isHibernateProxy()` and `isHibernateProxyMember()` with non-Hibernate objects. We need a test that verifies the short-circuit behavior works correctly. Add this test to `StrutsProxyServiceTest.java`: + +```java +@Test +public void isHibernateProxyDoesNotThrowWhenCalledRepeatedly() { + // Verify that calling isHibernateProxy many times for different objects + // does not cause performance issues (no exceptions thrown internally) + for (int i = 0; i < 1000; i++) { + assertThat(proxyService.isHibernateProxy(new Object())).isFalse(); + } +} + +@Test +public void isHibernateProxyMemberDoesNotThrowWhenCalledRepeatedly() throws NoSuchMethodException { + Method method = Object.class.getMethod("toString"); + for (int i = 0; i < 1000; i++) { + assertThat(proxyService.isHibernateProxyMember(method)).isFalse(); + } +} +``` + +- [ ] **Step 2: Run tests to verify they pass (baseline — these pass even without the fix because Hibernate IS on the test classpath)** + +Run: `mvn test -DskipAssembly -pl core -Dtest=StrutsProxyServiceTest#isHibernateProxyDoesNotThrowWhenCalledRepeatedly+isHibernateProxyMemberDoesNotThrowWhenCalledRepeatedly` +Expected: PASS + +- [ ] **Step 3: Add static Hibernate availability flag to StrutsProxyService** + +In `core/src/main/java/org/apache/struts2/util/StrutsProxyService.java`, add a static availability check at the top of the class and modify the three Hibernate methods to short-circuit: + +```java +// Add this field near the top of the class, after the class declaration: +private static final boolean HIBERNATE_AVAILABLE = isHibernateAvailable(); + +private static boolean isHibernateAvailable() { + try { + Class.forName("org.hibernate.proxy.HibernateProxy"); + return true; + } catch (ClassNotFoundException e) { + return false; + } +} +``` + +Then modify the three Hibernate methods to short-circuit: + +**`isHibernateProxy`** — change from: +```java +@Override +public boolean isHibernateProxy(Object object) { + try { + return object != null && HibernateProxy.class.isAssignableFrom(object.getClass()); + } catch (LinkageError ignored) { + return false; + } +} +``` +to: +```java +@Override +public boolean isHibernateProxy(Object object) { + if (!HIBERNATE_AVAILABLE || object == null) { + return false; + } + try { + return HibernateProxy.class.isAssignableFrom(object.getClass()); + } catch (LinkageError ignored) { + return false; + } +} +``` + +**`isHibernateProxyMember`** — change from: +```java +@Override +public boolean isHibernateProxyMember(Member member) { + try { + return hasMember(HibernateProxy.class, member); + } catch (LinkageError ignored) { + return false; + } +} +``` +to: +```java +@Override +public boolean isHibernateProxyMember(Member member) { + if (!HIBERNATE_AVAILABLE) { + return false; + } + try { + return hasMember(HibernateProxy.class, member); + } catch (LinkageError ignored) { + return false; + } +} +``` + +**`getHibernateProxyTarget`** — change from: +```java +@Override +public Object getHibernateProxyTarget(Object object) { + try { + return Hibernate.unproxy(object); + } catch (LinkageError ignored) { + return object; + } +} +``` +to: +```java +@Override +public Object getHibernateProxyTarget(Object object) { + if (!HIBERNATE_AVAILABLE) { + return object; + } + try { + return Hibernate.unproxy(object); + } catch (LinkageError ignored) { + return object; + } +} +``` + +- [ ] **Step 4: Run the full StrutsProxyService test suite** + +Run: `mvn test -DskipAssembly -pl core -Dtest=StrutsProxyServiceTest` +Expected: All tests PASS + +- [ ] **Step 5: Run the Spring integration test suite** + +Run: `mvn test -DskipAssembly -pl core -Dtest=StrutsProxyServiceSpringIntegrationTest` +Expected: All tests PASS + +- [ ] **Step 6: Commit** + +```bash +git add core/src/main/java/org/apache/struts2/util/StrutsProxyService.java core/src/test/java/org/apache/struts2/util/StrutsProxyServiceTest.java +git commit -m "WW-5622 Optimize Hibernate proxy detection to avoid LinkageError exceptions + +Add static availability check for Hibernate classes in StrutsProxyService. +When Hibernate is not on the classpath, all Hibernate-related methods +short-circuit immediately without throwing/catching LinkageError. +This eliminates a significant performance penalty for applications +that don't use Hibernate." +``` + +--- + +### Task 2: Apply Same Fix to Deprecated ProxyUtil + +**Files:** +- Modify: `core/src/main/java/org/apache/struts2/util/ProxyUtil.java` + +- [ ] **Step 1: Add the same static availability check to ProxyUtil** + +In `core/src/main/java/org/apache/struts2/util/ProxyUtil.java`, add the same pattern: + +```java +// Add after the isProxyMemberCache field: +private static final boolean HIBERNATE_AVAILABLE = isHibernateAvailable(); + +private static boolean isHibernateAvailable() { + try { + Class.forName("org.hibernate.proxy.HibernateProxy"); + return true; + } catch (ClassNotFoundException e) { + return false; + } +} +``` + +Then modify the three Hibernate methods in ProxyUtil identically to Task 1: + +**`isHibernateProxy`**: +```java +@Deprecated(since = "7.2") +public static boolean isHibernateProxy(Object object) { + if (!HIBERNATE_AVAILABLE || object == null) { + return false; + } + try { + return HibernateProxy.class.isAssignableFrom(object.getClass()); + } catch (LinkageError ignored) { + return false; + } +} +``` + +**`isHibernateProxyMember`**: +```java +@Deprecated(since = "7.2") +public static boolean isHibernateProxyMember(Member member) { + if (!HIBERNATE_AVAILABLE) { + return false; + } + try { + return hasMember(HibernateProxy.class, member); + } catch (LinkageError ignored) { + return false; + } +} +``` + +**`getHibernateProxyTarget`**: +```java +@Deprecated(since = "7.2") +public static Object getHibernateProxyTarget(Object object) { + if (!HIBERNATE_AVAILABLE) { + return object; + } + try { + return Hibernate.unproxy(object); + } catch (LinkageError ignored) { + return object; + } +} +``` + +- [ ] **Step 2: Run existing ProxyUtil tests** + +Run: `mvn test -DskipAssembly -pl core -Dtest=ProxyUtilTest` +Expected: PASS (or if no dedicated test exists, run the SecurityMemberAccess tests which exercise ProxyUtil indirectly) + +Run: `mvn test -DskipAssembly -pl core -Dtest=SecurityMemberAccessTest` +Expected: PASS + +- [ ] **Step 3: Commit** + +```bash +git add core/src/main/java/org/apache/struts2/util/ProxyUtil.java +git commit -m "WW-5622 Apply same Hibernate availability optimization to deprecated ProxyUtil" +``` + +--- + +### Task 3: Run Full Test Suite + +- [ ] **Step 1: Run all core tests** + +Run: `mvn test -DskipAssembly -pl core` +Expected: All tests PASS + +- [ ] **Step 2: Run spring plugin tests (exercises proxy detection heavily)** + +Run: `mvn test -DskipAssembly -pl plugins/spring` +Expected: All tests PASS + +- [ ] **Step 3: Run json plugin tests (StrutsJSONWriter has Hibernate-related class name checks)** + +Run: `mvn test -DskipAssembly -pl plugins/json` +Expected: All tests PASS diff --git a/docs/superpowers/plans/2026-04-06-ognl-3.5-upgrade.md b/docs/superpowers/plans/2026-04-06-ognl-3.5-upgrade.md new file mode 100644 index 0000000000..ed90cb9547 --- /dev/null +++ b/docs/superpowers/plans/2026-04-06-ognl-3.5-upgrade.md @@ -0,0 +1,1032 @@ +# OGNL 3.5.x Upgrade Implementation Plan + +> **Jira:** [WW-5326](https://issues.apache.org/jira/browse/WW-5326) +> +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Upgrade Struts from OGNL 3.4.10 to 3.5.0-BETA4, introducing `StrutsContext extends OgnlContext` and parameterizing all OGNL interface implementations with the new generic type. + +**Architecture:** Direct `StrutsContext` construction replaces `Ognl.createDefaultContext()`. All OGNL interfaces (`MemberAccess`, `PropertyAccessor`, `MethodAccessor`, `ClassResolver`, `TypeConverter`, `NullHandler`) gain `` type parameter. No behavioral changes — same security model, same accessor logic, same expression evaluation. + +**Tech Stack:** Java 17+, OGNL 3.5.0-BETA4, Maven, JUnit 5, AssertJ, Mockito + +--- + +## File Map + +### New Files +- `core/src/main/java/org/apache/struts2/ognl/StrutsContext.java` — Struts' OgnlContext subclass +- `core/src/test/java/org/apache/struts2/ognl/StrutsContextTest.java` — Unit tests for StrutsContext + +### Modified Files — Core Main (21 files) + +**Interfaces:** +- `core/src/main/java/org/apache/struts2/ognl/accessor/RootAccessor.java` — add `` to `PropertyAccessor`, `MethodAccessor`, `ClassResolver` + +**MemberAccess / TypeConverter / NullHandler:** +- `core/src/main/java/org/apache/struts2/ognl/SecurityMemberAccess.java` — `implements MemberAccess`, change method params +- `core/src/main/java/org/apache/struts2/ognl/OgnlTypeConverterWrapper.java` — `implements ognl.TypeConverter`, change method params +- `core/src/main/java/org/apache/struts2/ognl/XWorkTypeConverterWrapper.java` — update `convertValue` to use `StrutsContext` +- `core/src/main/java/org/apache/struts2/ognl/OgnlNullHandlerWrapper.java` — `implements ognl.NullHandler`, change method params + +**PropertyAccessor implementations:** +- `core/src/main/java/org/apache/struts2/ognl/accessor/CompoundRootAccessor.java` — all method params `OgnlContext` → `StrutsContext` +- `core/src/main/java/org/apache/struts2/ognl/accessor/ObjectAccessor.java` — `extends ObjectPropertyAccessor` +- `core/src/main/java/org/apache/struts2/ognl/accessor/ObjectProxyPropertyAccessor.java` — `implements PropertyAccessor` +- `core/src/main/java/org/apache/struts2/ognl/accessor/ParameterPropertyAccessor.java` — `extends ObjectPropertyAccessor` +- `core/src/main/java/org/apache/struts2/ognl/accessor/HttpParametersPropertyAccessor.java` — `extends ObjectPropertyAccessor` +- `core/src/main/java/org/apache/struts2/ognl/accessor/XWorkObjectPropertyAccessor.java` — `extends ObjectPropertyAccessor` +- `core/src/main/java/org/apache/struts2/ognl/accessor/XWorkCollectionPropertyAccessor.java` — `extends SetPropertyAccessor` +- `core/src/main/java/org/apache/struts2/ognl/accessor/XWorkEnumerationAccessor.java` — `extends EnumerationPropertyAccessor` +- `core/src/main/java/org/apache/struts2/ognl/accessor/XWorkIteratorPropertyAccessor.java` — `extends IteratorPropertyAccessor` +- `core/src/main/java/org/apache/struts2/ognl/accessor/XWorkListPropertyAccessor.java` — `extends ListPropertyAccessor` +- `core/src/main/java/org/apache/struts2/ognl/accessor/XWorkMapPropertyAccessor.java` — `extends MapPropertyAccessor` +- `core/src/main/java/org/apache/struts2/ognl/accessor/XWorkMethodAccessor.java` — `extends ObjectMethodAccessor` + +**Context creation / evaluation:** +- `core/src/main/java/org/apache/struts2/ognl/OgnlUtil.java` — `createDefaultContext` returns `StrutsContext`, `ensureOgnlContext` returns `StrutsContext`, `withRoot` takes `StrutsContext`, casts updated +- `core/src/main/java/org/apache/struts2/ognl/OgnlValueStack.java` — `setRoot` creates `StrutsContext` directly, field type `Map context` → `StrutsContext context` +- `core/src/main/java/org/apache/struts2/ognl/OgnlValueStackFactory.java` — update `OgnlRuntime.setPropertyAccessor`/`setMethodAccessor` calls (may need raw types at boundary) +- `core/src/main/java/org/apache/struts2/ognl/OgnlReflectionContextFactory.java` — deprecated, minimal change or remove + +### Modified Files — Core Main (non-OGNL package, 1 file) +- `core/src/main/java/org/apache/struts2/conversion/impl/DefaultTypeConverter.java` — imports `OgnlContext`, may need `StrutsContext` + +### Modified Files — POM (1 file) +- `pom.xml` — bump `ognl.version` from `3.4.10` to `3.5.0-BETA4` + +### Modified Files — Tiles Plugin Main (5 files) +- `plugins/tiles/src/main/java/org/apache/tiles/ognl/AnyScopePropertyAccessor.java` +- `plugins/tiles/src/main/java/org/apache/tiles/ognl/ScopePropertyAccessor.java` +- `plugins/tiles/src/main/java/org/apache/tiles/ognl/DelegatePropertyAccessor.java` +- `plugins/tiles/src/main/java/org/apache/tiles/ognl/NestedObjectDelegatePropertyAccessor.java` +- `plugins/tiles/src/main/java/org/apache/tiles/ognl/PropertyAccessorDelegateFactory.java` + +### Modified Files — Test (varies) +- Test files that create `OgnlContext` via `Ognl.createDefaultContext()` need updating +- Key tests: `SecurityMemberAccessTest`, `OgnlUtilTest`, `SecurityMemberAccessProxyTest` + +--- + +### Task 1: Bump OGNL Version + +**Files:** +- Modify: `pom.xml:126` + +- [ ] **Step 1: Update OGNL version property** + +In `pom.xml`, change the `ognl.version` property: + +```xml + +3.4.10 + + +3.5.0-BETA4 +``` + +- [ ] **Step 2: Verify dependency resolves** + +Run: `mvn dependency:resolve -pl core -DskipAssembly 2>&1 | tail -20` + +Expected: OGNL 3.5.0-BETA4 resolves successfully. Build will NOT compile yet — that's expected. + +- [ ] **Step 3: Commit** + +```bash +git add pom.xml +git commit -m "WW-5326 build(deps): bump OGNL from 3.4.10 to 3.5.0-BETA4" +``` + +--- + +### Task 2: Create StrutsContext + +**Files:** +- Create: `core/src/main/java/org/apache/struts2/ognl/StrutsContext.java` +- Create: `core/src/test/java/org/apache/struts2/ognl/StrutsContextTest.java` + +- [ ] **Step 1: Write the test** + +```java +package org.apache.struts2.ognl; + +import ognl.ClassResolver; +import ognl.MemberAccess; +import ognl.TypeConverter; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +@SuppressWarnings("unchecked") +class StrutsContextTest { + + @Test + void shouldCreateContextWithRequiredMemberAccess() { + MemberAccess memberAccess = mock(MemberAccess.class); + var context = new StrutsContext(memberAccess); + + assertThat(context).isNotNull(); + assertThat(context.getMemberAccess()).isSameAs(memberAccess); + } + + @Test + void shouldCreateContextWithAllComponents() { + MemberAccess memberAccess = mock(MemberAccess.class); + ClassResolver classResolver = mock(ClassResolver.class); + TypeConverter typeConverter = mock(TypeConverter.class); + + var context = new StrutsContext(memberAccess, classResolver, typeConverter); + + assertThat(context.getMemberAccess()).isSameAs(memberAccess); + assertThat(context.getClassResolver()).isSameAs(classResolver); + assertThat(context.getTypeConverter()).isSameAs(typeConverter); + } + + @Test + void shouldSupportRootObject() { + MemberAccess memberAccess = mock(MemberAccess.class); + var root = new Object(); + var context = new StrutsContext(memberAccess); + context.withRoot(root); + + assertThat(context.getRoot()).isSameAs(root); + } + + @Test + void shouldImplementMapInterface() { + MemberAccess memberAccess = mock(MemberAccess.class); + var context = new StrutsContext(memberAccess); + + context.put("testKey", "testValue"); + assertThat(context.get("testKey")).isEqualTo("testValue"); + } +} +``` + +- [ ] **Step 2: Run test to verify it fails** + +Run: `mvn test -DskipAssembly -pl core -Dtest=StrutsContextTest -Dsurefire.failIfNoSpecifiedTests=false 2>&1 | tail -10` + +Expected: FAIL — `StrutsContext` class does not exist yet. + +- [ ] **Step 3: Create StrutsContext class** + +```java +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.struts2.ognl; + +import ognl.ClassResolver; +import ognl.MemberAccess; +import ognl.OgnlContext; +import ognl.TypeConverter; + +/** + * Struts-specific OGNL evaluation context. Extends {@link OgnlContext} with the + * self-bounded generic parameter to enable type-safe access in all OGNL interface + * implementations ({@link MemberAccess}, {@link ognl.PropertyAccessor}, etc.). + * + *

Phase 1: minimal subclass delegating to super constructors. + * Future phases will promote stringly-typed map entries (e.g. {@code DENY_METHOD_EXECUTION}, + * {@code CREATE_NULL_OBJECTS}) to proper typed fields.

+ * + * @since 7.2.0 + */ +public class StrutsContext extends OgnlContext { + + public StrutsContext(MemberAccess memberAccess) { + super(memberAccess); + } + + public StrutsContext(MemberAccess memberAccess, + ClassResolver classResolver) { + super(memberAccess, classResolver); + } + + public StrutsContext(MemberAccess memberAccess, + ClassResolver classResolver, + TypeConverter typeConverter) { + super(memberAccess, classResolver, typeConverter); + } +} +``` + +- [ ] **Step 4: Run test to verify it passes** + +Run: `mvn test -DskipAssembly -pl core -Dtest=StrutsContextTest 2>&1 | tail -10` + +Expected: All 4 tests PASS. + +- [ ] **Step 5: Commit** + +```bash +git add core/src/main/java/org/apache/struts2/ognl/StrutsContext.java core/src/test/java/org/apache/struts2/ognl/StrutsContextTest.java +git commit -m "WW-5326 feat(ognl): introduce StrutsContext extending OgnlContext" +``` + +--- + +### Task 3: Update Core Interfaces — RootAccessor, MemberAccess, TypeConverter, NullHandler + +These are the top-level interface/wrapper changes. Nothing compiles yet — that's fine, we're working through the type ripple. + +**Files:** +- Modify: `core/src/main/java/org/apache/struts2/ognl/accessor/RootAccessor.java` +- Modify: `core/src/main/java/org/apache/struts2/ognl/SecurityMemberAccess.java` +- Modify: `core/src/main/java/org/apache/struts2/ognl/OgnlTypeConverterWrapper.java` +- Modify: `core/src/main/java/org/apache/struts2/ognl/XWorkTypeConverterWrapper.java` +- Modify: `core/src/main/java/org/apache/struts2/ognl/OgnlNullHandlerWrapper.java` + +- [ ] **Step 1: Update RootAccessor interface** + +In `core/src/main/java/org/apache/struts2/ognl/accessor/RootAccessor.java`: + +```java +package org.apache.struts2.ognl.accessor; + +import ognl.ClassResolver; +import ognl.MethodAccessor; +import ognl.PropertyAccessor; +import org.apache.struts2.ognl.StrutsContext; + +/** + * @since 6.4.0 + */ +public interface RootAccessor extends PropertyAccessor, MethodAccessor, ClassResolver { +} +``` + +- [ ] **Step 2: Update SecurityMemberAccess** + +In `core/src/main/java/org/apache/struts2/ognl/SecurityMemberAccess.java`: + +Change the class declaration: + +```java +// Before +public class SecurityMemberAccess implements MemberAccess { +// After +public class SecurityMemberAccess implements MemberAccess { +``` + +Change the import from `import ognl.OgnlContext;` to `import org.apache.struts2.ognl.StrutsContext;` (remove the OgnlContext import if no longer needed). + +Change all three method signatures: + +```java +// Before +public Object setup(OgnlContext context, Object target, Member member, String propertyName) { +// After +public Object setup(StrutsContext context, Object target, Member member, String propertyName) { + +// Before +public void restore(OgnlContext context, Object target, Member member, String propertyName, Object state) { +// After +public void restore(StrutsContext context, Object target, Member member, String propertyName, Object state) { + +// Before +public boolean isAccessible(OgnlContext context, Object target, Member member, String propertyName) { +// After +public boolean isAccessible(StrutsContext context, Object target, Member member, String propertyName) { +``` + +- [ ] **Step 3: Update OgnlTypeConverterWrapper** + +In `core/src/main/java/org/apache/struts2/ognl/OgnlTypeConverterWrapper.java`: + +```java +// Before +public class OgnlTypeConverterWrapper implements ognl.TypeConverter { +// After +public class OgnlTypeConverterWrapper implements ognl.TypeConverter { + +// Before +public Object convertValue(OgnlContext context, Object target, Member member, String propertyName, Object value, Class toType) { +// After +public Object convertValue(StrutsContext context, Object target, Member member, String propertyName, Object value, Class toType) { +``` + +Replace `import ognl.OgnlContext;` with `// no longer needed` (remove it) since the method now takes `StrutsContext`. + +- [ ] **Step 4: Update XWorkTypeConverterWrapper** + +In `core/src/main/java/org/apache/struts2/ognl/XWorkTypeConverterWrapper.java`: + +The `convertValue` method takes `Map context` and casts to `OgnlContext`. After the upgrade, `ognl.TypeConverter.convertValue` passes `StrutsContext` directly. But `XWorkTypeConverterWrapper` implements the *Struts* `TypeConverter` interface (which takes `Map`), not the OGNL one. So this file's changes are minimal — just update the cast: + +```java +// Before +OgnlContext ognlContext = (context instanceof OgnlContext oc) ? oc : null; +if (ognlContext == null) { + throw new IllegalArgumentException("Context must be an OgnlContext for OGNL 3.4.8+"); +} +return typeConverter.convertValue(ognlContext, target, member, propertyName, value, toType); + +// After +StrutsContext strutsContext = (context instanceof StrutsContext sc) ? sc : null; +if (strutsContext == null) { + throw new IllegalArgumentException("Context must be a StrutsContext"); +} +return typeConverter.convertValue(strutsContext, target, member, propertyName, value, toType); +``` + +Add `import org.apache.struts2.ognl.StrutsContext;` and remove the `import ognl.OgnlContext;`. + +- [ ] **Step 5: Update OgnlNullHandlerWrapper** + +In `core/src/main/java/org/apache/struts2/ognl/OgnlNullHandlerWrapper.java`: + +```java +// Before +public class OgnlNullHandlerWrapper implements ognl.NullHandler { +// After +public class OgnlNullHandlerWrapper implements ognl.NullHandler { + +// Before +public Object nullMethodResult(OgnlContext context, Object target, String methodName, Object[] args) { +// After +public Object nullMethodResult(StrutsContext context, Object target, String methodName, Object[] args) { + +// Before +public Object nullPropertyValue(OgnlContext context, Object target, Object property) { +// After +public Object nullPropertyValue(StrutsContext context, Object target, Object property) { +``` + +Replace `import ognl.OgnlContext;` with `// removed`. + +- [ ] **Step 6: Commit** + +```bash +git add core/src/main/java/org/apache/struts2/ognl/accessor/RootAccessor.java \ + core/src/main/java/org/apache/struts2/ognl/SecurityMemberAccess.java \ + core/src/main/java/org/apache/struts2/ognl/OgnlTypeConverterWrapper.java \ + core/src/main/java/org/apache/struts2/ognl/XWorkTypeConverterWrapper.java \ + core/src/main/java/org/apache/struts2/ognl/OgnlNullHandlerWrapper.java +git commit -m "WW-5326 refactor(ognl): parameterize core interfaces with StrutsContext" +``` + +--- + +### Task 4: Update PropertyAccessor Implementations + +All 13 accessor classes in `core/src/main/java/org/apache/struts2/ognl/accessor/`. The pattern is identical: add `` to the superclass/interface, change `OgnlContext` → `StrutsContext` in all method params. + +**Files:** +- Modify: `core/src/main/java/org/apache/struts2/ognl/accessor/CompoundRootAccessor.java` +- Modify: `core/src/main/java/org/apache/struts2/ognl/accessor/ObjectAccessor.java` +- Modify: `core/src/main/java/org/apache/struts2/ognl/accessor/ObjectProxyPropertyAccessor.java` +- Modify: `core/src/main/java/org/apache/struts2/ognl/accessor/ParameterPropertyAccessor.java` +- Modify: `core/src/main/java/org/apache/struts2/ognl/accessor/HttpParametersPropertyAccessor.java` +- Modify: `core/src/main/java/org/apache/struts2/ognl/accessor/XWorkObjectPropertyAccessor.java` +- Modify: `core/src/main/java/org/apache/struts2/ognl/accessor/XWorkCollectionPropertyAccessor.java` +- Modify: `core/src/main/java/org/apache/struts2/ognl/accessor/XWorkEnumerationAccessor.java` +- Modify: `core/src/main/java/org/apache/struts2/ognl/accessor/XWorkIteratorPropertyAccessor.java` +- Modify: `core/src/main/java/org/apache/struts2/ognl/accessor/XWorkListPropertyAccessor.java` +- Modify: `core/src/main/java/org/apache/struts2/ognl/accessor/XWorkMapPropertyAccessor.java` +- Modify: `core/src/main/java/org/apache/struts2/ognl/accessor/XWorkMethodAccessor.java` + +- [ ] **Step 1: Update CompoundRootAccessor** + +This is the largest accessor file. Change the class declaration (no change needed — it `implements RootAccessor` which is already parameterized). But all method signatures taking `OgnlContext` must change to `StrutsContext`: + +```java +// Add import +import org.apache.struts2.ognl.StrutsContext; + +// Change every method signature. Key methods: +public String getSourceAccessor(StrutsContext context, Object target, Object index) +public String getSourceSetter(StrutsContext context, Object target, Object index) +public void setProperty(StrutsContext context, Object target, Object name, Object value) throws OgnlException +public Object getProperty(StrutsContext context, Object target, Object name) throws OgnlException +public Object callMethod(StrutsContext context, Object target, String name, Object[] objects) throws MethodFailedException +public Object callStaticMethod(StrutsContext context, Class aClass, String s, Object[] objects) throws MethodFailedException +public Class classForName(String className, StrutsContext context) throws ClassNotFoundException +``` + +Remove `import ognl.OgnlContext;` if no longer used. + +- [ ] **Step 2: Update simple ObjectPropertyAccessor subclasses (6 files)** + +For each of these 6 files, apply the same pattern — add `` to the superclass and change `OgnlContext` → `StrutsContext` in method params: + +**ObjectAccessor.java:** +```java +import org.apache.struts2.ognl.StrutsContext; +// Before: public class ObjectAccessor extends ObjectPropertyAccessor { +public class ObjectAccessor extends ObjectPropertyAccessor { +// Before: public Object getProperty(OgnlContext map, Object o, Object o1) throws OgnlException { +public Object getProperty(StrutsContext map, Object o, Object o1) throws OgnlException { +``` + +**ParameterPropertyAccessor.java:** +```java +import org.apache.struts2.ognl.StrutsContext; +// Before: public class ParameterPropertyAccessor extends ObjectPropertyAccessor { +public class ParameterPropertyAccessor extends ObjectPropertyAccessor { +// Change both getProperty and setProperty params: OgnlContext → StrutsContext +``` + +**HttpParametersPropertyAccessor.java:** +```java +import org.apache.struts2.ognl.StrutsContext; +// Before: public class HttpParametersPropertyAccessor extends ObjectPropertyAccessor { +public class HttpParametersPropertyAccessor extends ObjectPropertyAccessor { +// Change both getProperty and setProperty params: OgnlContext → StrutsContext +``` + +**XWorkObjectPropertyAccessor.java:** +```java +import org.apache.struts2.ognl.StrutsContext; +// Before: public class XWorkObjectPropertyAccessor extends ObjectPropertyAccessor { +public class XWorkObjectPropertyAccessor extends ObjectPropertyAccessor { +// Change getProperty param: OgnlContext → StrutsContext +``` + +**XWorkEnumerationAccessor.java:** +```java +import org.apache.struts2.ognl.StrutsContext; +// Before: public class XWorkEnumerationAccessor extends EnumerationPropertyAccessor { +public class XWorkEnumerationAccessor extends EnumerationPropertyAccessor { +// Change setProperty param: OgnlContext → StrutsContext +// Also change the ObjectPropertyAccessor import if needed +``` + +**XWorkIteratorPropertyAccessor.java:** +```java +import org.apache.struts2.ognl.StrutsContext; +// Before: public class XWorkIteratorPropertyAccessor extends IteratorPropertyAccessor { +public class XWorkIteratorPropertyAccessor extends IteratorPropertyAccessor { +// Change setProperty param: OgnlContext → StrutsContext +// Also extends ObjectPropertyAccessor reference in import +``` + +- [ ] **Step 3: Update ObjectProxyPropertyAccessor** + +```java +import org.apache.struts2.ognl.StrutsContext; +// Before: public class ObjectProxyPropertyAccessor implements PropertyAccessor { +public class ObjectProxyPropertyAccessor implements PropertyAccessor { + +// Change ALL method params: OgnlContext → StrutsContext +// getSourceAccessor, getSourceSetter, getProperty, setProperty, setupContext (private) +``` + +- [ ] **Step 4: Update XWorkCollectionPropertyAccessor** + +```java +import org.apache.struts2.ognl.StrutsContext; +// Before: public class XWorkCollectionPropertyAccessor extends SetPropertyAccessor { +public class XWorkCollectionPropertyAccessor extends SetPropertyAccessor { + +// Change ALL method params: OgnlContext → StrutsContext +// getProperty, getSetMap, getPropertyThroughIteration, setProperty, getRealValue +``` + +- [ ] **Step 5: Update XWorkListPropertyAccessor** + +```java +import org.apache.struts2.ognl.StrutsContext; +// Before: public class XWorkListPropertyAccessor extends ListPropertyAccessor { +public class XWorkListPropertyAccessor extends ListPropertyAccessor { + +// Change ALL method params: OgnlContext → StrutsContext +// getProperty, setProperty, getRealValue +// Also: the field type `XWorkCollectionPropertyAccessor _sAcc` and setter `setXWorkCollectionPropertyAccessor(PropertyAccessor acc)` — the PropertyAccessor param needs `` too +``` + +```java +// Before: public void setXWorkCollectionPropertyAccessor(PropertyAccessor acc) { +public void setXWorkCollectionPropertyAccessor(PropertyAccessor acc) { +``` + +- [ ] **Step 6: Update XWorkMapPropertyAccessor** + +```java +import org.apache.struts2.ognl.StrutsContext; +// Before: public class XWorkMapPropertyAccessor extends MapPropertyAccessor { +public class XWorkMapPropertyAccessor extends MapPropertyAccessor { + +// Change ALL method params: OgnlContext → StrutsContext +// getProperty, setProperty, getValue (private), getKey (private) +``` + +- [ ] **Step 7: Update XWorkMethodAccessor** + +```java +import org.apache.struts2.ognl.StrutsContext; +// Before: public class XWorkMethodAccessor extends ObjectMethodAccessor { +public class XWorkMethodAccessor extends ObjectMethodAccessor { + +// Change method params: OgnlContext → StrutsContext +// callMethod, callStaticMethod +``` + +- [ ] **Step 8: Commit** + +```bash +git add core/src/main/java/org/apache/struts2/ognl/accessor/ +git commit -m "WW-5326 refactor(ognl): parameterize all accessor implementations with StrutsContext" +``` + +--- + +### Task 5: Update Context Creation — OgnlUtil, OgnlValueStack, OgnlValueStackFactory + +**Files:** +- Modify: `core/src/main/java/org/apache/struts2/ognl/OgnlUtil.java` +- Modify: `core/src/main/java/org/apache/struts2/ognl/OgnlValueStack.java` +- Modify: `core/src/main/java/org/apache/struts2/ognl/OgnlValueStackFactory.java` +- Modify: `core/src/main/java/org/apache/struts2/ognl/OgnlReflectionContextFactory.java` + +- [ ] **Step 1: Update OgnlUtil** + +Key changes in `core/src/main/java/org/apache/struts2/ognl/OgnlUtil.java`: + +Add import: +```java +import org.apache.struts2.ognl.StrutsContext; +``` + +Change `createDefaultContext` methods (lines 727-738): +```java +// Before +protected OgnlContext createDefaultContext(Object root) { + return createDefaultContext(root, null); +} + +protected OgnlContext createDefaultContext(Object root, ClassResolver resolver) { + if (resolver == null) { + resolver = container.getInstance(RootAccessor.class); + if (resolver == null) { + throw new IllegalStateException("Cannot find ClassResolver"); + } + } + return Ognl.createDefaultContext(root, container.getInstance(SecurityMemberAccess.class), resolver, defaultConverter); +} + +// After +protected StrutsContext createDefaultContext(Object root) { + return createDefaultContext(root, null); +} + +protected StrutsContext createDefaultContext(Object root, ClassResolver resolver) { + if (resolver == null) { + resolver = container.getInstance(RootAccessor.class); + if (resolver == null) { + throw new IllegalStateException("Cannot find ClassResolver"); + } + } + StrutsContext context = new StrutsContext( + container.getInstance(SecurityMemberAccess.class), resolver, defaultConverter); + context.withRoot(root); + return context; +} +``` + +Change `ensureOgnlContext` (lines 214-222): +```java +// Before +private OgnlContext ensureOgnlContext(Map context) { + if (context instanceof OgnlContext ognlContext) { + return ognlContext; + } + OgnlContext ognlContext = createDefaultContext(null); + ognlContext.putAll(context); + return ognlContext; +} + +// After +private StrutsContext ensureOgnlContext(Map context) { + if (context instanceof StrutsContext strutsContext) { + return strutsContext; + } + StrutsContext strutsContext = createDefaultContext(null); + strutsContext.putAll(context); + return strutsContext; +} +``` + +Change `withRoot` helper methods (lines 765-794) — `OgnlContext` → `StrutsContext`: +```java +// Before +private void withRoot(OgnlContext context, Object root, OgnlAction action) throws OgnlException { +// After +private void withRoot(StrutsContext context, Object root, OgnlAction action) throws OgnlException { + +// Before +private T withRoot(OgnlContext context, Object root, OgnlSupplier supplier) throws OgnlException { +// After +private T withRoot(StrutsContext context, Object root, OgnlSupplier supplier) throws OgnlException { +``` + +Change `ognlSet` and `ognlGet` casts (lines 427, 437): +```java +// Before +OgnlContext ognlContext = (OgnlContext) context; +// After +StrutsContext ognlContext = (StrutsContext) context; +``` + +Change `defaultConverter` field type (line 64): +```java +// Before +private TypeConverter defaultConverter; +// After — note: this is ognl.TypeConverter +private TypeConverter defaultConverter; +``` + +Update `setXWorkConverter` (line 92): +```java +// The OgnlTypeConverterWrapper now implements TypeConverter, so this is compatible +``` + +Update import: `import ognl.TypeConverter;` stays, but the `ClassResolver` import needs to be checked. Also change any remaining `OgnlContext` references in method signatures throughout the file to `StrutsContext`. + +- [ ] **Step 2: Update OgnlValueStack** + +Key changes in `core/src/main/java/org/apache/struts2/ognl/OgnlValueStack.java`: + +Change field type (line 71): +```java +// Before +protected transient Map context; +// After +protected transient StrutsContext context; +``` + +Add import: +```java +import org.apache.struts2.ognl.StrutsContext; +``` + +Change `setRoot` method (lines 121-130): +```java +// Before +protected void setRoot(XWorkConverter xworkConverter, RootAccessor accessor, CompoundRoot compoundRoot, SecurityMemberAccess securityMemberAccess) { + this.root = compoundRoot; + this.securityMemberAccess = securityMemberAccess; + OgnlContext ognlContext = Ognl.createDefaultContext(this.root, securityMemberAccess, accessor, new OgnlTypeConverterWrapper(xworkConverter)); + this.context = ognlContext; + this.converter = xworkConverter; + context.put(VALUE_STACK, this); + ognlContext.setTraceEvaluations(false); + ognlContext.setKeepLastEvaluation(false); +} + +// After +protected void setRoot(XWorkConverter xworkConverter, RootAccessor accessor, CompoundRoot compoundRoot, SecurityMemberAccess securityMemberAccess) { + this.root = compoundRoot; + this.securityMemberAccess = securityMemberAccess; + this.context = new StrutsContext(securityMemberAccess, accessor, new OgnlTypeConverterWrapper(xworkConverter)); + this.context.withRoot(this.root); + this.converter = xworkConverter; + context.put(VALUE_STACK, this); + context.setTraceEvaluations(false); + context.setKeepLastEvaluation(false); +} +``` + +Remove `import ognl.OgnlContext;` if no longer needed. Keep `import ognl.Ognl;` only if still used elsewhere in the file. + +Update `getContext()` return type if it currently returns `Map` — check the `ValueStack` interface. The `ValueStack.getContext()` returns `Map`, which `StrutsContext` satisfies (since `OgnlContext` implements `Map`). No interface change needed. + +- [ ] **Step 3: Update OgnlValueStackFactory** + +In `core/src/main/java/org/apache/struts2/ognl/OgnlValueStackFactory.java`: + +The `OgnlRuntime.setPropertyAccessor()` and `OgnlRuntime.setMethodAccessor()` calls now expect generic types. Since `OgnlRuntime` methods are static with their own generic parameter, and the accessors are now `PropertyAccessor` / `MethodAccessor`, this should work. But the `Container.getInstance(PropertyAccessor.class)` returns a raw type. Add `@SuppressWarnings("unchecked")` where needed: + +```java +// In registerPropertyAccessors(), the existing code should work since OgnlRuntime +// accepts the raw type at the boundary. If compiler errors occur, add: +@SuppressWarnings({"rawtypes", "unchecked"}) +``` + +- [ ] **Step 4: Update OgnlReflectionContextFactory** + +This class is `@Deprecated(forRemoval=true)`. Minimal change — keep it working with raw types: + +```java +@Override +public OgnlContext createDefaultContext(Object root) { + return Ognl.createDefaultContext(root); +} +``` + +This returns raw `OgnlContext` from the static OGNL method. Since the class is deprecated, this is acceptable. No change may even be needed if the raw type compiles. + +- [ ] **Step 5: Compile core module** + +Run: `mvn compile -DskipAssembly -pl core 2>&1 | tail -30` + +Expected: Core compiles. Fix any remaining type errors discovered here. + +- [ ] **Step 6: Commit** + +```bash +git add core/src/main/java/org/apache/struts2/ognl/OgnlUtil.java \ + core/src/main/java/org/apache/struts2/ognl/OgnlValueStack.java \ + core/src/main/java/org/apache/struts2/ognl/OgnlValueStackFactory.java \ + core/src/main/java/org/apache/struts2/ognl/OgnlReflectionContextFactory.java +git commit -m "WW-5326 refactor(ognl): replace Ognl.createDefaultContext with direct StrutsContext construction" +``` + +--- + +### Task 6: Update Tiles Plugin + +The tiles plugin accessors use raw `PropertyAccessor` and take `OgnlContext` in method params. Since tiles runs inside Struts, parameterize with `StrutsContext`. + +**Files:** +- Modify: `plugins/tiles/src/main/java/org/apache/tiles/ognl/AnyScopePropertyAccessor.java` +- Modify: `plugins/tiles/src/main/java/org/apache/tiles/ognl/ScopePropertyAccessor.java` +- Modify: `plugins/tiles/src/main/java/org/apache/tiles/ognl/DelegatePropertyAccessor.java` +- Modify: `plugins/tiles/src/main/java/org/apache/tiles/ognl/NestedObjectDelegatePropertyAccessor.java` +- Modify: `plugins/tiles/src/main/java/org/apache/tiles/ognl/PropertyAccessorDelegateFactory.java` +- Modify: `plugins/tiles/src/main/java/org/apache/tiles/ognl/TilesContextPropertyAccessorDelegateFactory.java` + +- [ ] **Step 1: Update AnyScopePropertyAccessor** + +```java +import org.apache.struts2.ognl.StrutsContext; +// Before: public class AnyScopePropertyAccessor implements PropertyAccessor { +public class AnyScopePropertyAccessor implements PropertyAccessor { + +// Change all 4 method params: OgnlContext → StrutsContext +``` + +- [ ] **Step 2: Update ScopePropertyAccessor** + +Same pattern as AnyScopePropertyAccessor: +```java +import org.apache.struts2.ognl.StrutsContext; +// Before: public class ScopePropertyAccessor implements PropertyAccessor { +public class ScopePropertyAccessor implements PropertyAccessor { + +// Change all 4 method params: OgnlContext → StrutsContext +``` + +- [ ] **Step 3: Update PropertyAccessorDelegateFactory** + +```java +import ognl.PropertyAccessor; +import org.apache.struts2.ognl.StrutsContext; + +public interface PropertyAccessorDelegateFactory { + // Before: PropertyAccessor getPropertyAccessor(String propertyName, T obj); + PropertyAccessor getPropertyAccessor(String propertyName, T obj); +} +``` + +- [ ] **Step 4: Update TilesContextPropertyAccessorDelegateFactory** + +Update field types and constructor params: +```java +import org.apache.struts2.ognl.StrutsContext; + +// Before: private final PropertyAccessor objectPropertyAccessor; +private final PropertyAccessor objectPropertyAccessor; +// Same for applicationContextPropertyAccessor, anyScopePropertyAccessor, scopePropertyAccessor + +// Constructor params: +public TilesContextPropertyAccessorDelegateFactory( + PropertyAccessor objectPropertyAccessor, + PropertyAccessor applicationContextPropertyAccessor, + PropertyAccessor anyScopePropertyAccessor, + PropertyAccessor scopePropertyAccessor) + +// Return type: +public PropertyAccessor getPropertyAccessor(String propertyName, Request request) +``` + +- [ ] **Step 5: Update DelegatePropertyAccessor** + +```java +import org.apache.struts2.ognl.StrutsContext; +// Before: public class DelegatePropertyAccessor implements PropertyAccessor { +public class DelegatePropertyAccessor implements PropertyAccessor { + +// Before: private final PropertyAccessorDelegateFactory factory; +// (no change — factory return type already updated) + +// Change all 4 method params: OgnlContext → StrutsContext +``` + +- [ ] **Step 6: Update NestedObjectDelegatePropertyAccessor** + +```java +import org.apache.struts2.ognl.StrutsContext; +// Before: public class NestedObjectDelegatePropertyAccessor implements PropertyAccessor { +public class NestedObjectDelegatePropertyAccessor implements PropertyAccessor { + +// Before: private final PropertyAccessor propertyAccessor; +private final PropertyAccessor propertyAccessor; + +// Constructor: +public NestedObjectDelegatePropertyAccessor(NestedObjectExtractor nestedObjectExtractor, PropertyAccessor propertyAccessor) + +// Change all 4 method params: OgnlContext → StrutsContext +``` + +- [ ] **Step 7: Compile tiles plugin** + +Run: `mvn compile -DskipAssembly -pl plugins/tiles 2>&1 | tail -30` + +Expected: Compiles. Fix any remaining type issues. + +- [ ] **Step 8: Commit** + +```bash +git add plugins/tiles/src/main/java/org/apache/tiles/ognl/ +git commit -m "WW-5326 refactor(tiles): parameterize tiles OGNL accessors with StrutsContext" +``` + +--- + +### Task 7: Update Test Files + +Tests that create `OgnlContext` via `Ognl.createDefaultContext(null)` need to create `StrutsContext` instead. + +**Files:** +- Modify: `core/src/test/java/org/apache/struts2/ognl/SecurityMemberAccessTest.java` +- Modify: `plugins/spring/src/test/java/org/apache/struts2/ognl/SecurityMemberAccessProxyTest.java` +- Modify: Other test files as needed (compile will reveal them) + +- [ ] **Step 1: Update SecurityMemberAccessTest** + +In `core/src/test/java/org/apache/struts2/ognl/SecurityMemberAccessTest.java`: + +Change field type: +```java +// Before +private OgnlContext context; +// After +private StrutsContext context; +``` + +Change setUp: +```java +// Before +context = ognl.Ognl.createDefaultContext(null); +// After +context = new StrutsContext(sma); +``` + +Note: `sma` is initialized in `assignNewSma` which is called after this line. Reorder if needed — create `sma` first, then context. Check the setUp flow and adjust accordingly. The `assignNewSma` method creates a new `SecurityMemberAccess`, so context may need to be created after that call. + +Add import: +```java +import org.apache.struts2.ognl.StrutsContext; +``` + +Remove `import ognl.OgnlContext;` if no longer used. + +- [ ] **Step 2: Update SecurityMemberAccessProxyTest** + +In `plugins/spring/src/test/java/org/apache/struts2/ognl/SecurityMemberAccessProxyTest.java`: + +Same pattern: +```java +// Before +private OgnlContext context; +... +context = ognl.Ognl.createDefaultContext(null); +// After +private StrutsContext context; +... +context = new StrutsContext(sma); +``` + +- [ ] **Step 3: Fix remaining test compilation errors** + +Run: `mvn test-compile -DskipAssembly -pl core 2>&1 | grep "error:" | head -30` + +Fix each error. Most will be `OgnlContext` → `StrutsContext` type changes or `Ognl.createDefaultContext()` calls that need replacing. + +Run: `mvn test-compile -DskipAssembly -pl plugins/tiles 2>&1 | grep "error:" | head -30` + +Fix tiles test compilation errors similarly. + +Run: `mvn test-compile -DskipAssembly -pl plugins/spring 2>&1 | grep "error:" | head -30` + +Fix spring test compilation errors. + +- [ ] **Step 4: Commit** + +```bash +git add -u +git commit -m "WW-5326 test(ognl): update tests for StrutsContext migration" +``` + +--- + +### Task 8: Run Full Test Suite and Fix Failures + +- [ ] **Step 1: Run core tests** + +Run: `mvn test -DskipAssembly -pl core 2>&1 | tail -30` + +Expected: All tests pass. If failures occur, investigate and fix. Common issues: +- `ClassCastException` if OGNL internally creates raw `OgnlContext` instead of preserving `StrutsContext` +- `OgnlRuntime` accessor registration warnings with generic types +- Test setup creating wrong context type + +- [ ] **Step 2: Run tiles plugin tests** + +Run: `mvn test -DskipAssembly -pl plugins/tiles 2>&1 | tail -30` + +Expected: All tests pass. + +- [ ] **Step 3: Run spring plugin tests** + +Run: `mvn test -DskipAssembly -pl plugins/spring 2>&1 | tail -30` + +Expected: All tests pass. + +- [ ] **Step 4: Run full build** + +Run: `mvn test -DskipAssembly 2>&1 | tail -50` + +Expected: Full build succeeds with all tests passing. This catches any transitive compilation issues in other modules. + +- [ ] **Step 5: Commit any remaining fixes** + +```bash +git add -u +git commit -m "WW-5326 fix(ognl): resolve test failures from OGNL 3.5.x migration" +``` + +--- + +### Task 9: Cleanup and Final Verification + +- [ ] **Step 1: Search for any remaining raw OgnlContext usage** + +Run grep to find leftover `OgnlContext` references that should be `StrutsContext`: + +```bash +# In core main sources (excluding deprecated OgnlReflectionContextFactory) +grep -rn "OgnlContext" core/src/main/java/ --include="*.java" | grep -v "OgnlReflectionContextFactory" | grep -v "import" +``` + +Any results (other than Javadoc or string literals) indicate missed conversions. Fix them. + +- [ ] **Step 2: Search for remaining `Ognl.createDefaultContext` calls** + +```bash +grep -rn "Ognl.createDefaultContext" core/src/main/java/ --include="*.java" | grep -v "OgnlReflectionContextFactory" +``` + +Expected: No results (except the deprecated factory). All context creation should go through `new StrutsContext(...)` or `OgnlUtil.createDefaultContext()`. + +- [ ] **Step 3: Run full build one final time** + +Run: `mvn clean test -DskipAssembly 2>&1 | tail -30` + +Expected: Clean build, all tests pass. + +- [ ] **Step 4: Commit any final cleanup** + +```bash +git add -u +git commit -m "WW-5326 chore(ognl): cleanup remaining OgnlContext references" +``` + +--- + +## Notes for the Implementer + +### Known Risk: OgnlRuntime Generic Boundary + +`OgnlValueStackFactory` registers accessors via `OgnlRuntime.setPropertyAccessor(Class, PropertyAccessor)`. Since these are now `PropertyAccessor` but the `OgnlRuntime` method is generic with its own ``, you may need `@SuppressWarnings("unchecked")` at the registration boundary. This is acceptable — it's a type-erasure boundary between Struts' typed world and OGNL's static global registry. + +### Known Risk: OGNL Internal Context Preservation + +If any test fails with `ClassCastException` (trying to cast `OgnlContext` to `StrutsContext`), it means OGNL internally creates a new `OgnlContext` during evaluation instead of preserving the passed-in `StrutsContext`. **This is a bug in OGNL 3.5.x** that should be reported upstream. Workaround: use `instanceof` checks at the boundary. + +### Deprecated `Ognl.setRoot()` → `context.withRoot()` + +OGNL 3.5.x deprecates `Ognl.setRoot(context, root)` in favor of `context.withRoot(root)`. The `OgnlUtil.withRoot()` helper method currently uses `Ognl.setRoot()` / `Ognl.getRoot()`. Update to use `context.withRoot()` / `context.getRoot()` directly. + +### The `DefaultTypeConverter` File + +`core/src/main/java/org/apache/struts2/conversion/impl/DefaultTypeConverter.java` imports `ognl.OgnlContext` but only uses it in a conditional cast. Check whether this cast needs updating to `StrutsContext` or if it can use the `Map` interface. diff --git a/docs/superpowers/specs/2026-04-06-ognl-3.5-upgrade-design.md b/docs/superpowers/specs/2026-04-06-ognl-3.5-upgrade-design.md new file mode 100644 index 0000000000..9358d8e9b5 --- /dev/null +++ b/docs/superpowers/specs/2026-04-06-ognl-3.5-upgrade-design.md @@ -0,0 +1,263 @@ +# OGNL 3.5.x Upgrade — Design Spec + +> **Jira:** [WW-5326](https://issues.apache.org/jira/browse/WW-5326) + +## Goal + +Upgrade Apache Struts from OGNL 3.4.10 to OGNL 3.5.0-BETA4+ and introduce `StrutsContext extends OgnlContext` as the framework's own OGNL evaluation context. This lays the foundation for treating OGNL as an execution sandbox with typed, Struts-specific context state. + +## Motivation + +- **Forward-looking maintenance**: stay current with OGNL development, avoid a larger migration later +- **Real-world validation**: Struts is the primary consumer of OGNL — upgrading validates the 3.5.x generic API +- **Java 17 baseline**: OGNL 3.5.x requires Java 17, aligning with Struts 7.x +- **Type safety**: self-bounded generics (`OgnlContext`) enable Struts to have a properly typed context instead of stringly-typed map entries +- **Sandbox foundation**: `StrutsContext` is the first step toward isolated OGNL evaluation contexts (`OgnlRuntime` instance-based isolation is future work) + +## Non-Goals + +- Instance-based `OgnlRuntime` / true sandbox isolation (future OGNL work) +- Consuming new OGNL features (null-safe operator `?.`, dual-mode evaluation) — those come as separate follow-ups +- Behavioral changes to security model, accessor logic, or expression evaluation + +## Current State + +### OGNL Usage in Struts + +- **Version**: 3.4.10 (defined in root `pom.xml` as `ognl.version`) +- **Core dependency**: `core/pom.xml` depends on `ognl:ognl` +- **Context creation**: 3 call sites use `Ognl.createDefaultContext()`: + - `OgnlUtil.createDefaultContext()` (line 738) + - `OgnlValueStack.setRoot()` (line 124) + - `OgnlReflectionContextFactory.createDefaultContext()` (line 33) +- **No custom OgnlContext subclass**: Struts uses `OgnlContext` directly +- **Context state via map entries**: flags like `DENY_METHOD_EXECUTION`, `CREATE_NULL_OBJECTS`, `VALUE_STACK`, conversion state — all stored as stringly-typed map entries in `OgnlContext` and accessed via `ReflectionContextState` static methods + +### OGNL Interface Implementations in Struts + +| Interface | Struts Implementation | +|---|---| +| `MemberAccess` | `SecurityMemberAccess` | +| `TypeConverter` | `OgnlTypeConverterWrapper` | +| `ClassResolver` | `RootAccessor` (interface), `CompoundRootAccessor` (impl) | +| `PropertyAccessor` | `RootAccessor`, `CompoundRootAccessor`, `ObjectProxyPropertyAccessor`, + 8 classes extending `ObjectPropertyAccessor`/`ListPropertyAccessor`/`MapPropertyAccessor`/etc. | +| `MethodAccessor` | `RootAccessor`, `CompoundRootAccessor`, `XWorkMethodAccessor` | +| `NullHandler` | `OgnlNullHandlerWrapper` | + +### Tiles Plugin OGNL Usage + +6-8 files in `plugins/tiles` use OGNL directly: +- `ScopePropertyAccessor`, `AnyScopePropertyAccessor`, `NestedObjectDelegatePropertyAccessor`, `DelegatePropertyAccessor` +- `OGNLAttributeEvaluator`, `PropertyAccessorDelegateFactory`, `TilesContextPropertyAccessorDelegateFactory` +- Associated test files + +## OGNL 3.5.x Key API Changes + +### Self-Bounded Generics + +All core interfaces and classes are now generic with `>`: + +```java +public class OgnlContext> implements Map +public interface MemberAccess> +public interface ClassResolver> +public interface TypeConverter> +public interface PropertyAccessor> +public interface MethodAccessor> +public interface NullHandler> +public class ObjectPropertyAccessor> implements PropertyAccessor +// ... all base accessor classes similarly parameterized +``` + +### OgnlContext Constructor Changes + +```java +// New (memberAccess first, required non-null) +public OgnlContext(MemberAccess memberAccess, ClassResolver classResolver, TypeConverter typeConverter) + +// Deprecated (old parameter order) +@Deprecated(forRemoval = true) +OgnlContext(ClassResolver classResolver, TypeConverter typeConverter, MemberAccess memberAccess) +``` + +### OgnlContext.Builder + +```java +public static class Builder> { + public Builder(Function, C> provider) + public Builder withMemberAccess(MemberAccess memberAccess) + public Builder withClassResolver(ClassResolver classResolver) + public Builder withTypeConverter(TypeConverter converter) + public Builder withRoot(Object value) + public C build() +} +``` + +### Other Changes + +- `SecurityManager` support removed +- Null-safe navigation operator (`?.`) added +- `setRoot()` deprecated in favor of `withRoot()` (fluent) +- Java 17 baseline + +### Unchanged + +- `Ognl` class remains abstract with only static methods (no instance-based evaluation) +- `OgnlRuntime` remains a static utility (global accessor/cache registration) + +## Design + +### Approach: Direct StrutsContext Construction + +Struts creates `StrutsContext` directly, bypassing `Ognl.createDefaultContext()`. This gives Struts full ownership of context lifecycle and avoids the global-state issues of `Ognl.withBuilderProvider()`. + +### StrutsContext + +```java +package org.apache.struts2.ognl; + +public class StrutsContext extends OgnlContext { + + // Phase 1: just the constructor, delegate to super + public StrutsContext(SecurityMemberAccess memberAccess, + RootAccessor resolver, + OgnlTypeConverterWrapper converter) { + super(memberAccess, resolver, converter); + } + + // Phase 2 (incremental): promote map entries to typed fields + // private ValueStack valueStack; + // private boolean reportErrorsOnNoProperty; + // private boolean throwExceptionOnFailure; + // private boolean createNullObjects; + // private boolean denyMethodExecution; + // private boolean denyIndexedAccessExecution; + // private String conversionPropertyFullName; + // private String currentPropertyPath; + // private Class lastBeanClassAccessed; + // private String lastBeanPropertyAccessed; +} +``` + +Phase 1 introduces the class with zero behavioral change — it's just an `OgnlContext` subclass. The typed fields are a follow-up. + +### Generic Type Ripple + +All OGNL interface implementations parameterize with ``: + +```java +// Core interfaces +public class SecurityMemberAccess implements MemberAccess +public class OgnlTypeConverterWrapper implements ognl.TypeConverter +public interface RootAccessor extends PropertyAccessor, MethodAccessor, ClassResolver +public class OgnlNullHandlerWrapper implements ognl.NullHandler + +// Accessors (extend generic base classes) +public class CompoundRootAccessor implements RootAccessor +public class ObjectProxyPropertyAccessor implements PropertyAccessor +public class ObjectAccessor extends ObjectPropertyAccessor +public class ParameterPropertyAccessor extends ObjectPropertyAccessor +public class HttpParametersPropertyAccessor extends ObjectPropertyAccessor +public class XWorkObjectPropertyAccessor extends ObjectPropertyAccessor +public class XWorkEnumerationAccessor extends EnumerationPropertyAccessor // verify base class +public class XWorkIteratorPropertyAccessor extends IteratorPropertyAccessor // verify base class +public class XWorkCollectionPropertyAccessor extends ObjectPropertyAccessor +public class XWorkListPropertyAccessor extends ListPropertyAccessor +public class XWorkMapPropertyAccessor extends MapPropertyAccessor +public class XWorkMethodAccessor extends ObjectMethodAccessor +``` + +Method signatures change `OgnlContext` parameters to `StrutsContext` throughout. + +### Context Creation + +Replace `Ognl.createDefaultContext()` with direct construction: + +```java +// OgnlUtil.createDefaultContext() +protected StrutsContext createDefaultContext(Object root, ClassResolver resolver) { + if (resolver == null) { + resolver = container.getInstance(RootAccessor.class); + } + StrutsContext ctx = new StrutsContext( + container.getInstance(SecurityMemberAccess.class), resolver, defaultConverter); + ctx.withRoot(root); + return ctx; +} + +// OgnlValueStack.setRoot() +StrutsContext ognlContext = new StrutsContext(securityMemberAccess, accessor, + new OgnlTypeConverterWrapper(xworkConverter)); +ognlContext.withRoot(this.root); + +// OgnlReflectionContextFactory — already @Deprecated(forRemoval=true) since 6.8.0 +// Keep using Ognl.createDefaultContext(root) with raw type, or remove entirely +``` + +### Tiles Plugin + +The tiles plugin accessors operate on tiles-specific objects, not on `StrutsContext` directly. Options: +- Parameterize with raw `OgnlContext` (use `PropertyAccessor`) if OGNL allows it +- Use wildcard `PropertyAccessor` if supported +- Parameterize with `StrutsContext` if tiles always runs within a Struts context + +Decision: determine during implementation based on what compiles cleanly. + +### XWorkTypeConverterWrapper + +Currently casts `Map` context to `OgnlContext`. After upgrade, `ognl.TypeConverter` passes `StrutsContext` directly — the cast goes away. Struts' own `TypeConverter` interface (in `conversion` package) may also need its `convertValue` signature updated. + +### ReflectionContextState + +Initially unchanged — continues to work via `Map` interface that `StrutsContext` inherits from `OgnlContext`. Promoting to typed fields is a follow-up. + +## Implementation Phases + +### Phase 1: Version bump + StrutsContext + generics (this effort) + +1. Bump `ognl.version` to `3.5.0-BETA4` in root `pom.xml` +2. Create `StrutsContext extends OgnlContext` (constructor only) +3. Update all OGNL interface implementations with `` type parameter (~20 classes in core) +4. Update method signatures: `OgnlContext` → `StrutsContext` in all accessor/handler implementations +5. Replace `Ognl.createDefaultContext()` with direct `StrutsContext` construction (3 call sites) +6. Update tiles plugin accessor classes (~6-8 files) +7. Update test files (~50+ files referencing `OgnlContext`) +8. Verify all tests pass + +### Phase 2: Typed context fields (follow-up) + +- Promote `ReflectionContextState` map entries to `StrutsContext` typed fields +- Update accessors to use typed getters instead of `context.get("string.key")` +- Deprecate `ReflectionContextState` static methods + +### Phase 3: Sandbox features (future, requires OGNL changes) + +- Instance-based `OgnlRuntime` (OGNL-side work) +- Per-sandbox accessor registrations +- Isolated evaluation engines + +## Risk Areas + +### OgnlRuntime global statics + +`OgnlRuntime.setPropertyAccessor(Class, PropertyAccessor)` is generic but the registration is global. Registering `PropertyAccessor` may cause unchecked warnings or issues when OGNL internally retrieves accessors with a different context type. May need raw types at registration boundary. + +### OGNL internal context preservation + +If OGNL internally creates new `OgnlContext` instances during expression evaluation (rather than preserving the passed-in `StrutsContext`), typed fields would be lost. BETA1 addressed "context root preservation during nested evaluations" but this needs runtime verification. + +### Tiles plugin type compatibility + +Tiles accessors may not naturally fit `StrutsContext` parameterization. Need to determine the right generic type during implementation. + +### OGNL BETA stability + +OGNL 3.5.0 is still in BETA. API changes may occur in subsequent releases. This is acceptable given the user is an OGNL contributor and can influence the API. + +## Expected Outcomes + +- Struts compiles and all tests pass against OGNL 3.5.0-BETA4 +- `StrutsContext` exists as the framework's OGNL context class +- All OGNL interface implementations are properly parameterized with `` +- Foundation is in place for typed context fields and eventual sandbox isolation +- Any OGNL API issues discovered are reported/fixed upstream diff --git a/plugins/spring/src/test/java/org/apache/struts2/ognl/SecurityMemberAccessProxyTest.java b/plugins/spring/src/test/java/org/apache/struts2/ognl/SecurityMemberAccessProxyTest.java index 526d528ab7..e9195ced68 100644 --- a/plugins/spring/src/test/java/org/apache/struts2/ognl/SecurityMemberAccessProxyTest.java +++ b/plugins/spring/src/test/java/org/apache/struts2/ognl/SecurityMemberAccessProxyTest.java @@ -28,7 +28,7 @@ import org.junit.Test; import org.springframework.aop.MethodBeforeAdvice; import org.springframework.aop.framework.ProxyFactory; -import ognl.OgnlContext; +import org.apache.struts2.ognl.StrutsContext; import java.lang.reflect.Member; import java.lang.reflect.Method; @@ -43,7 +43,7 @@ public class SecurityMemberAccessProxyTest extends XWorkJUnit4TestCase { private static final String PROXY_MEMBER_METHOD = "isExposeProxy"; private static final String TEST_SUB_BEAN_CLASS_METHOD = "getIssueId"; - private OgnlContext context; + private StrutsContext context; private ActionProxy proxy; private SecurityMemberAccess sma; private ProxyService proxyService; @@ -57,14 +57,13 @@ public void setUp() throws Exception { XmlConfigurationProvider provider = new StrutsXmlConfigurationProvider("org/apache/struts2/spring/actionContext-xwork.xml"); loadConfigurationProviders(provider); - context = ognl.Ognl.createDefaultContext(null); - proxy = actionProxyFactory.createActionProxy(null, "chaintoAOPedTestSubBeanAction", null, context); - proxyObjectProxyMember = proxy.getAction().getClass().getMethod(PROXY_MEMBER_METHOD); - proxyObjectNonProxyMember = proxy.getAction().getClass().getMethod(TEST_SUB_BEAN_CLASS_METHOD); - proxyService = new StrutsProxyService(new StrutsProxyCacheFactory<>("1000", "basic")); sma = new SecurityMemberAccess(null, null); sma.setProxyService(proxyService); + context = new StrutsContext(sma); + proxy = actionProxyFactory.createActionProxy(null, "chaintoAOPedTestSubBeanAction", null, context); + proxyObjectProxyMember = proxy.getAction().getClass().getMethod(PROXY_MEMBER_METHOD); + proxyObjectNonProxyMember = proxy.getAction().getClass().getMethod(TEST_SUB_BEAN_CLASS_METHOD); } /** diff --git a/plugins/tiles/src/main/java/org/apache/tiles/ognl/AnyScopePropertyAccessor.java b/plugins/tiles/src/main/java/org/apache/tiles/ognl/AnyScopePropertyAccessor.java index d3a108ca0d..71b257f446 100644 --- a/plugins/tiles/src/main/java/org/apache/tiles/ognl/AnyScopePropertyAccessor.java +++ b/plugins/tiles/src/main/java/org/apache/tiles/ognl/AnyScopePropertyAccessor.java @@ -27,6 +27,7 @@ /** * Accesses attributes in any scope. */ +@SuppressWarnings("rawtypes") public class AnyScopePropertyAccessor implements PropertyAccessor { @Override diff --git a/plugins/tiles/src/main/java/org/apache/tiles/ognl/DelegatePropertyAccessor.java b/plugins/tiles/src/main/java/org/apache/tiles/ognl/DelegatePropertyAccessor.java index 5567f33b23..cdee5e66ac 100644 --- a/plugins/tiles/src/main/java/org/apache/tiles/ognl/DelegatePropertyAccessor.java +++ b/plugins/tiles/src/main/java/org/apache/tiles/ognl/DelegatePropertyAccessor.java @@ -29,6 +29,7 @@ * @param The type of the accessed root object. * @since 2.2.0 */ +@SuppressWarnings("rawtypes") public class DelegatePropertyAccessor implements PropertyAccessor { /** diff --git a/plugins/tiles/src/main/java/org/apache/tiles/ognl/NestedObjectDelegatePropertyAccessor.java b/plugins/tiles/src/main/java/org/apache/tiles/ognl/NestedObjectDelegatePropertyAccessor.java index b966a0e115..d6be8a7a60 100644 --- a/plugins/tiles/src/main/java/org/apache/tiles/ognl/NestedObjectDelegatePropertyAccessor.java +++ b/plugins/tiles/src/main/java/org/apache/tiles/ognl/NestedObjectDelegatePropertyAccessor.java @@ -29,6 +29,7 @@ * @param The root object type from which the target object will be extracted. * @since 2.2.0 */ +@SuppressWarnings("rawtypes") public class NestedObjectDelegatePropertyAccessor implements PropertyAccessor { /** diff --git a/plugins/tiles/src/main/java/org/apache/tiles/ognl/PropertyAccessorDelegateFactory.java b/plugins/tiles/src/main/java/org/apache/tiles/ognl/PropertyAccessorDelegateFactory.java index b781b402a2..e1fd3d729d 100644 --- a/plugins/tiles/src/main/java/org/apache/tiles/ognl/PropertyAccessorDelegateFactory.java +++ b/plugins/tiles/src/main/java/org/apache/tiles/ognl/PropertyAccessorDelegateFactory.java @@ -28,6 +28,7 @@ * @param The type of the root object to evaluate. * @since 2.2.0 */ +@SuppressWarnings("rawtypes") public interface PropertyAccessorDelegateFactory { /** diff --git a/plugins/tiles/src/main/java/org/apache/tiles/ognl/ScopePropertyAccessor.java b/plugins/tiles/src/main/java/org/apache/tiles/ognl/ScopePropertyAccessor.java index 39a90eaaa6..75235229b8 100644 --- a/plugins/tiles/src/main/java/org/apache/tiles/ognl/ScopePropertyAccessor.java +++ b/plugins/tiles/src/main/java/org/apache/tiles/ognl/ScopePropertyAccessor.java @@ -25,6 +25,7 @@ /** * Accesses a scope. */ +@SuppressWarnings("rawtypes") public class ScopePropertyAccessor implements PropertyAccessor { /** diff --git a/pom.xml b/pom.xml index cbe39cf895..a382fbbc52 100644 --- a/pom.xml +++ b/pom.xml @@ -123,7 +123,7 @@ 4.0.7 2.25.4 5.23.0 - 3.4.10 + 3.5.0-BETA4 2.0.17 6.2.12 2.0 @@ -314,6 +314,7 @@ src/main/webapp/fonts/**/* thoughts/**/*.md test-output/** + docs/**