WW-5326 fix(tiles): use raw OgnlContext in tiles accessors

Tiles accessors are called by OGNL internal machinery with raw OgnlContext,
not within a Struts evaluation context, so they cannot use StrutsContext.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Lukasz Lenart
2026-04-06 19:27:16 +02:00
parent 803b5cbbd0
commit 6374e31384
9 changed files with 65 additions and 62 deletions
@@ -9,10 +9,10 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
@SuppressWarnings("unchecked")
class StrutsContextTest {
public class StrutsContextTest {
@Test
void shouldCreateContextWithRequiredMemberAccess() {
public void shouldCreateContextWithRequiredMemberAccess() {
MemberAccess<StrutsContext> memberAccess = mock(MemberAccess.class);
var context = new StrutsContext(memberAccess);
@@ -21,7 +21,7 @@ class StrutsContextTest {
}
@Test
void shouldCreateContextWithAllComponents() {
public void shouldCreateContextWithAllComponents() {
MemberAccess<StrutsContext> memberAccess = mock(MemberAccess.class);
ClassResolver<StrutsContext> classResolver = mock(ClassResolver.class);
TypeConverter<StrutsContext> typeConverter = mock(TypeConverter.class);
@@ -34,7 +34,7 @@ class StrutsContextTest {
}
@Test
void shouldSupportRootObject() {
public void shouldSupportRootObject() {
MemberAccess<StrutsContext> memberAccess = mock(MemberAccess.class);
var root = new Object();
var context = new StrutsContext(memberAccess);
@@ -44,7 +44,7 @@ class StrutsContextTest {
}
@Test
void shouldImplementMapInterface() {
public void shouldImplementMapInterface() {
MemberAccess<StrutsContext> memberAccess = mock(MemberAccess.class);
var context = new StrutsContext(memberAccess);
@@ -18,8 +18,8 @@
*/
package org.apache.tiles.ognl;
import ognl.OgnlContext;
import ognl.PropertyAccessor;
import org.apache.struts2.ognl.StrutsContext;
import org.apache.tiles.request.Request;
import java.util.Map;
@@ -27,10 +27,11 @@ import java.util.Map;
/**
* Accesses attributes in any scope.
*/
public class AnyScopePropertyAccessor implements PropertyAccessor<StrutsContext> {
@SuppressWarnings("rawtypes")
public class AnyScopePropertyAccessor implements PropertyAccessor {
@Override
public Object getProperty(StrutsContext context, Object target, Object name) {
public Object getProperty(OgnlContext context, Object target, Object name) {
Request request = (Request) target;
String attributeName = (String) name;
for (String scopeName : request.getAvailableScopes()) {
@@ -43,7 +44,7 @@ public class AnyScopePropertyAccessor implements PropertyAccessor<StrutsContext>
}
@Override
public String getSourceAccessor(StrutsContext context, Object target, Object index) {
public String getSourceAccessor(OgnlContext context, Object target, Object index) {
Request request = (Request) target;
String attributeName = (String) index;
for (String scopeName : request.getAvailableScopes()) {
@@ -56,7 +57,7 @@ public class AnyScopePropertyAccessor implements PropertyAccessor<StrutsContext>
}
@Override
public String getSourceSetter(StrutsContext context, Object target, Object index) {
public String getSourceSetter(OgnlContext context, Object target, Object index) {
Request request = (Request) target;
String attributeName = (String) index;
String[] availableScopes = request.getAvailableScopes().toArray(new String[0]);
@@ -70,7 +71,7 @@ public class AnyScopePropertyAccessor implements PropertyAccessor<StrutsContext>
}
@Override
public void setProperty(StrutsContext context, Object target, Object name, Object value) {
public void setProperty(OgnlContext context, Object target, Object name, Object value) {
Request request = (Request) target;
String attributeName = (String) name;
String[] availableScopes = request.getAvailableScopes().toArray(new String[0]);
@@ -18,9 +18,9 @@
*/
package org.apache.tiles.ognl;
import ognl.OgnlContext;
import ognl.OgnlException;
import ognl.PropertyAccessor;
import org.apache.struts2.ognl.StrutsContext;
/**
* Uses a {@link PropertyAccessorDelegateFactory} to delegate the methods to
@@ -29,7 +29,8 @@ import org.apache.struts2.ognl.StrutsContext;
* @param <T> The type of the accessed root object.
* @since 2.2.0
*/
public class DelegatePropertyAccessor<T> implements PropertyAccessor<StrutsContext> {
@SuppressWarnings("rawtypes")
public class DelegatePropertyAccessor<T> implements PropertyAccessor {
/**
* The property accessor factory.
@@ -52,7 +53,7 @@ public class DelegatePropertyAccessor<T> implements PropertyAccessor<StrutsConte
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
public Object getProperty(StrutsContext context, Object target, Object name) throws OgnlException {
public Object getProperty(OgnlContext context, Object target, Object name) throws OgnlException {
return factory.getPropertyAccessor((String) name, (T) target).getProperty(context, target, name);
}
@@ -60,7 +61,7 @@ public class DelegatePropertyAccessor<T> implements PropertyAccessor<StrutsConte
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
public void setProperty(StrutsContext context, Object target, Object name, Object value) throws OgnlException {
public void setProperty(OgnlContext context, Object target, Object name, Object value) throws OgnlException {
factory.getPropertyAccessor((String) name, (T) target).setProperty(context, target, name, value);
}
@@ -68,7 +69,7 @@ public class DelegatePropertyAccessor<T> implements PropertyAccessor<StrutsConte
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
public String getSourceAccessor(StrutsContext context, Object target, Object index) {
public String getSourceAccessor(OgnlContext context, Object target, Object index) {
return factory.getPropertyAccessor((String) index, (T) target).getSourceAccessor(context, target, index);
}
@@ -76,7 +77,7 @@ public class DelegatePropertyAccessor<T> implements PropertyAccessor<StrutsConte
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
public String getSourceSetter(StrutsContext context, Object target, Object index) {
public String getSourceSetter(OgnlContext context, Object target, Object index) {
return factory.getPropertyAccessor((String) index, (T) target).getSourceSetter(context, target, index);
}
}
@@ -18,9 +18,9 @@
*/
package org.apache.tiles.ognl;
import ognl.OgnlContext;
import ognl.OgnlException;
import ognl.PropertyAccessor;
import org.apache.struts2.ognl.StrutsContext;
/**
* Uses a {@link PropertyAccessor} as a delegate, but passing a nested object as
@@ -29,7 +29,8 @@ import org.apache.struts2.ognl.StrutsContext;
* @param <T> The root object type from which the target object will be extracted.
* @since 2.2.0
*/
public class NestedObjectDelegatePropertyAccessor<T> implements PropertyAccessor<StrutsContext> {
@SuppressWarnings("rawtypes")
public class NestedObjectDelegatePropertyAccessor<T> implements PropertyAccessor {
/**
* The extractor of the nested object.
@@ -43,7 +44,7 @@ public class NestedObjectDelegatePropertyAccessor<T> implements PropertyAccessor
*
* @since 2.2.0
*/
private final PropertyAccessor<StrutsContext> propertyAccessor;
private final PropertyAccessor propertyAccessor;
/**
* Constructor.
@@ -52,7 +53,7 @@ public class NestedObjectDelegatePropertyAccessor<T> implements PropertyAccessor
* @param propertyAccessor The delegated property accessor.
* @since 2.2.0
*/
public NestedObjectDelegatePropertyAccessor(NestedObjectExtractor<T> nestedObjectExtractor, PropertyAccessor<StrutsContext> propertyAccessor) {
public NestedObjectDelegatePropertyAccessor(NestedObjectExtractor<T> nestedObjectExtractor, PropertyAccessor propertyAccessor) {
this.nestedObjectExtractor = nestedObjectExtractor;
this.propertyAccessor = propertyAccessor;
}
@@ -61,7 +62,7 @@ public class NestedObjectDelegatePropertyAccessor<T> implements PropertyAccessor
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
public Object getProperty(StrutsContext context, Object target, Object name) throws OgnlException {
public Object getProperty(OgnlContext context, Object target, Object name) throws OgnlException {
return propertyAccessor.getProperty(context, nestedObjectExtractor.getNestedObject((T) target), name);
}
@@ -69,7 +70,7 @@ public class NestedObjectDelegatePropertyAccessor<T> implements PropertyAccessor
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
public void setProperty(StrutsContext context, Object target, Object name, Object value) throws OgnlException {
public void setProperty(OgnlContext context, Object target, Object name, Object value) throws OgnlException {
propertyAccessor.setProperty(context, nestedObjectExtractor.getNestedObject((T) target), name, value);
}
@@ -77,7 +78,7 @@ public class NestedObjectDelegatePropertyAccessor<T> implements PropertyAccessor
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
public String getSourceAccessor(StrutsContext context, Object target, Object index) {
public String getSourceAccessor(OgnlContext context, Object target, Object index) {
return propertyAccessor.getSourceAccessor(context, nestedObjectExtractor.getNestedObject((T) target), index);
}
@@ -85,7 +86,7 @@ public class NestedObjectDelegatePropertyAccessor<T> implements PropertyAccessor
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
public String getSourceSetter(StrutsContext context, Object target, Object index) {
public String getSourceSetter(OgnlContext context, Object target, Object index) {
return propertyAccessor.getSourceSetter(context, nestedObjectExtractor.getNestedObject((T) target), index);
}
}
@@ -20,7 +20,6 @@
package org.apache.tiles.ognl;
import ognl.PropertyAccessor;
import org.apache.struts2.ognl.StrutsContext;
/**
* Decides a {@link PropertyAccessor} depending on the property name and the
@@ -29,6 +28,7 @@ import org.apache.struts2.ognl.StrutsContext;
* @param <T> The type of the root object to evaluate.
* @since 2.2.0
*/
@SuppressWarnings("rawtypes")
public interface PropertyAccessorDelegateFactory<T> {
/**
@@ -40,5 +40,5 @@ public interface PropertyAccessorDelegateFactory<T> {
* @return The appropriate property accessor.
* @since 2.2.0
*/
PropertyAccessor<StrutsContext> getPropertyAccessor(String propertyName, T obj);
PropertyAccessor getPropertyAccessor(String propertyName, T obj);
}
@@ -18,14 +18,15 @@
*/
package org.apache.tiles.ognl;
import ognl.OgnlContext;
import ognl.PropertyAccessor;
import org.apache.struts2.ognl.StrutsContext;
import org.apache.tiles.request.Request;
/**
* Accesses a scope.
*/
public class ScopePropertyAccessor implements PropertyAccessor<StrutsContext> {
@SuppressWarnings("rawtypes")
public class ScopePropertyAccessor implements PropertyAccessor {
/**
* The length of the scope suffix: "Scope".
@@ -33,7 +34,7 @@ public class ScopePropertyAccessor implements PropertyAccessor<StrutsContext> {
static final int SCOPE_SUFFIX_LENGTH = 5;
@Override
public Object getProperty(StrutsContext context, Object target, Object name) {
public Object getProperty(OgnlContext context, Object target, Object name) {
Request request = (Request) target;
String scope = (String) name;
if (scope.endsWith("Scope")) {
@@ -44,7 +45,7 @@ public class ScopePropertyAccessor implements PropertyAccessor<StrutsContext> {
}
@Override
public String getSourceAccessor(StrutsContext context, Object target, Object index) {
public String getSourceAccessor(OgnlContext context, Object target, Object index) {
String scope = (String) index;
if (scope.endsWith("Scope")) {
String scopeName = scope.substring(0, scope.length() - SCOPE_SUFFIX_LENGTH);
@@ -54,12 +55,12 @@ public class ScopePropertyAccessor implements PropertyAccessor<StrutsContext> {
}
@Override
public String getSourceSetter(StrutsContext context, Object target, Object index) {
public String getSourceSetter(OgnlContext context, Object target, Object index) {
return null;
}
@Override
public void setProperty(StrutsContext context, Object target, Object name, Object value) {
public void setProperty(OgnlContext context, Object target, Object name, Object value) {
// Does nothing.
}
@@ -19,7 +19,6 @@
package org.apache.tiles.ognl;
import ognl.PropertyAccessor;
import org.apache.struts2.ognl.StrutsContext;
import org.apache.tiles.core.util.CombinedBeanInfo;
import org.apache.tiles.request.ApplicationContext;
import org.apache.tiles.request.Request;
@@ -36,22 +35,22 @@ public class TilesContextPropertyAccessorDelegateFactory implements PropertyAcce
* The plain object property accessor, to be used directly for
* {@link Request}.
*/
private final PropertyAccessor<StrutsContext> objectPropertyAccessor;
private final PropertyAccessor objectPropertyAccessor;
/**
* The application context property accessor.
*/
private final PropertyAccessor<StrutsContext> applicationContextPropertyAccessor;
private final PropertyAccessor applicationContextPropertyAccessor;
/**
* The request scope property accessor.
*/
private final PropertyAccessor<StrutsContext> anyScopePropertyAccessor;
private final PropertyAccessor anyScopePropertyAccessor;
/**
* The session scope property accessor.
*/
private final PropertyAccessor<StrutsContext> scopePropertyAccessor;
private final PropertyAccessor scopePropertyAccessor;
/**
* The bean info of {@link Request} and
@@ -71,10 +70,10 @@ public class TilesContextPropertyAccessorDelegateFactory implements PropertyAcce
* @since 2.2.0
*/
public TilesContextPropertyAccessorDelegateFactory(
PropertyAccessor<StrutsContext> objectPropertyAccessor,
PropertyAccessor<StrutsContext> applicationContextPropertyAccessor,
PropertyAccessor<StrutsContext> anyScopePropertyAccessor,
PropertyAccessor<StrutsContext> scopePropertyAccessor
PropertyAccessor objectPropertyAccessor,
PropertyAccessor applicationContextPropertyAccessor,
PropertyAccessor anyScopePropertyAccessor,
PropertyAccessor scopePropertyAccessor
) {
beanInfo = new CombinedBeanInfo(Request.class, ApplicationContext.class);
this.objectPropertyAccessor = objectPropertyAccessor;
@@ -84,8 +83,8 @@ public class TilesContextPropertyAccessorDelegateFactory implements PropertyAcce
}
/** {@inheritDoc} */
public PropertyAccessor<StrutsContext> getPropertyAccessor(String propertyName, Request request) {
PropertyAccessor<StrutsContext> retValue;
public PropertyAccessor getPropertyAccessor(String propertyName, Request request) {
PropertyAccessor retValue;
if (propertyName.endsWith("Scope")) {
String scopeName = propertyName.substring(0, propertyName.length() - ScopePropertyAccessor.SCOPE_SUFFIX_LENGTH);
if (request.getContext(scopeName) != null) {
@@ -19,9 +19,9 @@
package org.apache.tiles.ognl;
import ognl.OgnlContext;
import ognl.OgnlException;
import ognl.PropertyAccessor;
import org.apache.struts2.ognl.StrutsContext;
import org.junit.Test;
import static org.easymock.EasyMock.createMock;
@@ -36,7 +36,7 @@ import static org.junit.Assert.assertEquals;
public class DelegatePropertyAccessorTest {
/**
* Test method for {@link DelegatePropertyAccessor#getProperty(StrutsContext, Object, Object)}.
* Test method for {@link DelegatePropertyAccessor#getProperty(OgnlContext, Object, Object)}.
*
* @throws OgnlException If something goes wrong.
*/
@@ -44,7 +44,7 @@ public class DelegatePropertyAccessorTest {
public void testGetProperty() throws OgnlException {
PropertyAccessorDelegateFactory<Integer> factory = createMock(PropertyAccessorDelegateFactory.class);
PropertyAccessor mockAccessor = createMock(PropertyAccessor.class);
StrutsContext context = createMock(StrutsContext.class);
OgnlContext context = createMock(OgnlContext.class);
expect(factory.getPropertyAccessor("property", 1)).andReturn(mockAccessor);
expect(mockAccessor.getProperty(context, 1, "property")).andReturn("value");
@@ -55,7 +55,7 @@ public class DelegatePropertyAccessorTest {
}
/**
* Test method for {@link DelegatePropertyAccessor#setProperty(StrutsContext, Object, Object, Object)}.
* Test method for {@link DelegatePropertyAccessor#setProperty(OgnlContext, Object, Object, Object)}.
*
* @throws OgnlException If something goes wrong.
*/
@@ -63,7 +63,7 @@ public class DelegatePropertyAccessorTest {
public void testSetProperty() throws OgnlException {
PropertyAccessorDelegateFactory<Integer> factory = createMock(PropertyAccessorDelegateFactory.class);
PropertyAccessor mockAccessor = createMock(PropertyAccessor.class);
StrutsContext context = createMock(StrutsContext.class);
OgnlContext context = createMock(OgnlContext.class);
expect(factory.getPropertyAccessor("property", 1)).andReturn(mockAccessor);
mockAccessor.setProperty(context, 1, "property", "value");
@@ -74,13 +74,13 @@ public class DelegatePropertyAccessorTest {
}
/**
* Test method for {@link DelegatePropertyAccessor#getSourceAccessor(StrutsContext, Object, Object)}.
* Test method for {@link DelegatePropertyAccessor#getSourceAccessor(OgnlContext, Object, Object)}.
*/
@Test
public void testGetSourceAccessor() {
PropertyAccessorDelegateFactory<Integer> factory = createMock(PropertyAccessorDelegateFactory.class);
PropertyAccessor mockAccessor = createMock(PropertyAccessor.class);
StrutsContext context = createMock(StrutsContext.class);
OgnlContext context = createMock(OgnlContext.class);
expect(factory.getPropertyAccessor("property", 1)).andReturn(mockAccessor);
expect(mockAccessor.getSourceAccessor(context, 1, "property")).andReturn("method");
@@ -91,13 +91,13 @@ public class DelegatePropertyAccessorTest {
}
/**
* Test method for {@link DelegatePropertyAccessor#getSourceSetter(StrutsContext, Object, Object)}.
* Test method for {@link DelegatePropertyAccessor#getSourceSetter(OgnlContext, Object, Object)}.
*/
@Test
public void testGetSourceSetter() {
PropertyAccessorDelegateFactory<Integer> factory = createMock(PropertyAccessorDelegateFactory.class);
PropertyAccessor mockAccessor = createMock(PropertyAccessor.class);
StrutsContext context = createMock(StrutsContext.class);
OgnlContext context = createMock(OgnlContext.class);
expect(factory.getPropertyAccessor("property", 1)).andReturn(mockAccessor);
expect(mockAccessor.getSourceSetter(context, 1, "property")).andReturn("method");
@@ -18,9 +18,9 @@
*/
package org.apache.tiles.ognl;
import ognl.OgnlContext;
import ognl.OgnlException;
import ognl.PropertyAccessor;
import org.apache.struts2.ognl.StrutsContext;
import org.junit.Test;
import static org.easymock.EasyMock.*;
@@ -32,7 +32,7 @@ import static org.junit.Assert.assertEquals;
public class NestedObjectDelegatePropertyAccessorTest {
/**
* Test method for {@link NestedObjectDelegatePropertyAccessor#getProperty(StrutsContext, Object, Object)}.
* Test method for {@link NestedObjectDelegatePropertyAccessor#getProperty(OgnlContext, Object, Object)}.
*
* @throws OgnlException If something goes wrong.
*/
@@ -40,7 +40,7 @@ public class NestedObjectDelegatePropertyAccessorTest {
public void testGetProperty() throws OgnlException {
NestedObjectExtractor<Integer> nestedObjectExtractor = createMock(NestedObjectExtractor.class);
PropertyAccessor propertyAccessor = createMock(PropertyAccessor.class);
StrutsContext context = createMock(StrutsContext.class);
OgnlContext context = createMock(OgnlContext.class);
expect(propertyAccessor.getProperty(context, "nested", "property")).andReturn("value");
expect(nestedObjectExtractor.getNestedObject(1)).andReturn("nested");
@@ -51,7 +51,7 @@ public class NestedObjectDelegatePropertyAccessorTest {
}
/**
* Test method for {@link NestedObjectDelegatePropertyAccessor#setProperty(StrutsContext, Object, Object, Object)}.
* Test method for {@link NestedObjectDelegatePropertyAccessor#setProperty(OgnlContext, Object, Object, Object)}.
*
* @throws OgnlException If something goes wrong.
*/
@@ -59,7 +59,7 @@ public class NestedObjectDelegatePropertyAccessorTest {
public void testSetProperty() throws OgnlException {
NestedObjectExtractor<Integer> nestedObjectExtractor = createMock(NestedObjectExtractor.class);
PropertyAccessor propertyAccessor = createMock(PropertyAccessor.class);
StrutsContext context = createMock(StrutsContext.class);
OgnlContext context = createMock(OgnlContext.class);
propertyAccessor.setProperty(context, "nested", "property", "value");
expect(nestedObjectExtractor.getNestedObject(1)).andReturn("nested");
@@ -70,13 +70,13 @@ public class NestedObjectDelegatePropertyAccessorTest {
}
/**
* Test method for {@link NestedObjectDelegatePropertyAccessor#getSourceAccessor(StrutsContext, Object, Object)}.
* Test method for {@link NestedObjectDelegatePropertyAccessor#getSourceAccessor(OgnlContext, Object, Object)}.
*/
@Test
public void testGetSourceAccessor() {
NestedObjectExtractor<Integer> nestedObjectExtractor = createMock(NestedObjectExtractor.class);
PropertyAccessor propertyAccessor = createMock(PropertyAccessor.class);
StrutsContext context = createMock(StrutsContext.class);
OgnlContext context = createMock(OgnlContext.class);
expect(propertyAccessor.getSourceAccessor(context, "nested", "property")).andReturn("method");
expect(nestedObjectExtractor.getNestedObject(1)).andReturn("nested");
@@ -87,13 +87,13 @@ public class NestedObjectDelegatePropertyAccessorTest {
}
/**
* Test method for {@link NestedObjectDelegatePropertyAccessor#getSourceSetter(StrutsContext, Object, Object)}.
* Test method for {@link NestedObjectDelegatePropertyAccessor#getSourceSetter(OgnlContext, Object, Object)}.
*/
@Test
public void testGetSourceSetter() {
NestedObjectExtractor<Integer> nestedObjectExtractor = createMock(NestedObjectExtractor.class);
PropertyAccessor propertyAccessor = createMock(PropertyAccessor.class);
StrutsContext context = createMock(StrutsContext.class);
OgnlContext context = createMock(OgnlContext.class);
expect(propertyAccessor.getSourceSetter(context, "nested", "property")).andReturn("method");
expect(nestedObjectExtractor.getNestedObject(1)).andReturn("nested");