Commits

Anonymous committed 76778b7

Comments (0)

Files changed (6)

core/src/main/java/com/opensymphony/xwork2/config/providers/XWorkConfigurationProvider.java

         props.setProperty("devMode", Boolean.FALSE.toString());
         props.setProperty("logMissingProperties", Boolean.FALSE.toString());
         props.setProperty("enableOGNLExpressionCache", Boolean.TRUE.toString());
+        props.setProperty("enableSimpleParametersBinder", Boolean.FALSE.toString());
     }
 
 }

core/src/main/java/com/opensymphony/xwork2/interceptor/ParametersInterceptor.java

 import com.opensymphony.xwork2.ActionContext;
 import com.opensymphony.xwork2.ActionInvocation;
 import com.opensymphony.xwork2.ValidationAware;
+import com.opensymphony.xwork2.parameters.XWorkParametersBinder;
 import com.opensymphony.xwork2.conversion.impl.InstantiatingNullHandler;
 import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
 import com.opensymphony.xwork2.inject.Inject;
-import com.opensymphony.xwork2.util.ClearableValueStack;
-import com.opensymphony.xwork2.util.LocalizedTextUtil;
-import com.opensymphony.xwork2.util.MemberAccessValueStack;
-import com.opensymphony.xwork2.util.TextParseUtil;
-import com.opensymphony.xwork2.util.ValueStack;
-import com.opensymphony.xwork2.util.ValueStackFactory;
+import com.opensymphony.xwork2.util.*;
 import com.opensymphony.xwork2.util.logging.Logger;
 import com.opensymphony.xwork2.util.logging.LoggerFactory;
 import com.opensymphony.xwork2.util.reflection.ReflectionContextState;
 
     private ValueStackFactory valueStackFactory;
 
+    //only used if enableSimpleParametersBinder is true
+    private XWorkParametersBinder parametersBinder;
+    private boolean enableSimpleParametersBinder;
+
     @Inject
     public void setValueStackFactory(ValueStackFactory valueStackFactory) {
         this.valueStackFactory = valueStackFactory;
         devMode = "true".equals(mode);
     }
 
+    @Inject(value= "enableSimpleParametersBinder", required = false)
+    public void setEnableSimpleParametersBinder(String simpleBinder) {
+        this.enableSimpleParametersBinder = "true".equals(simpleBinder);
+    }
+
+    @Inject
+    public void setParametersBinder(XWorkParametersBinder parametersBinder) {
+        this.parametersBinder = parametersBinder;
+    }
+
     public void setAcceptParamNames(String commaDelim) {
         Collection<String> acceptPatterns = asCollection(commaDelim);
         if (acceptPatterns != null) {
             accessValueStack.setExcludeProperties(excludeParams);
         }
 
+        Map<String, Object> newContext = newStack.getContext();
+        CompoundRoot stackRoot = newStack.getRoot();
         for (Map.Entry<String, Object> entry : acceptableParameters.entrySet()) {
             String name = entry.getKey();
             Object value = entry.getValue();
             try {
-                newStack.setValue(name, value);
+                if (enableSimpleParametersBinder)
+                    parametersBinder.setProperty(newContext, stackRoot, name, value);
+                else
+                    newStack.setValue(name, value);
             } catch (RuntimeException e) {
                 if (devMode) {
                     String developerNotification = LocalizedTextUtil.findText(ParametersInterceptor.class, "devmode.notification", ActionContext.getContext().getLocale(), "Developer Notification:\n{0}", new Object[]{
             if (entry.getValue() instanceof Object[]) {
                 Object[] valueArray = (Object[]) entry.getValue();
                 logEntry.append("[ ");
-		if (valueArray.length > 0 ) {
+		        if (valueArray.length > 0 ) {
                     for (int indexA = 0; indexA < (valueArray.length - 1); indexA++) {
                         Object valueAtIndex = valueArray[indexA];
                         logEntry.append(String.valueOf(valueAtIndex));

core/src/main/java/com/opensymphony/xwork2/parameters/XWorkParametersBinder.java

 import com.opensymphony.xwork2.parameters.nodes.Node;
 import com.opensymphony.xwork2.parameters.nodes.IdentifierNode;
 import com.opensymphony.xwork2.parameters.nodes.IndexedNode;
+import com.opensymphony.xwork2.parameters.nodes.CollectionNode;
 import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
 import com.opensymphony.xwork2.util.reflection.ReflectionContextState;
+import com.opensymphony.xwork2.util.CompoundRoot;
 import com.opensymphony.xwork2.conversion.NullHandler;
+import com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor;
 
-import java.util.Map;
-import java.util.List;
-import java.util.Iterator;
-import java.util.Collection;
+import java.util.*;
 
 import org.apache.commons.lang.StringUtils;
 import ognl.PropertyAccessor;
     protected NullHandler nullHandler;
     protected Container container;
 
-    public void setProperty(Map<String, Object> context, Object action, String paramName, Object paramValue) throws ParseException, OgnlException {
-        if (StringUtils.isNotBlank(paramName)) {
+    public void setProperty(Map<String, Object> context, Object action, String paramName, Object paramValue) {
+        try {
             OgnlContext ognlContext = new OgnlContext(context);
-            
+
             XWorkParameterParser parser = new XWorkParameterParser(paramName);
             List<Node> nodes = parser.expression();
 
                     lastProperty = id;
 
                     //if this is not the last expression, create the object if it doesn't exist
-                    //Object value = reflectionProvider.getValue(id, ognlContext, lastObject);
                     PropertyAccessor accessor = getPropertyAccessor(lastObject);
-                    Object value = accessor.getProperty(ognlContext, action, id);
+                    Object value = accessor.getProperty(ognlContext, lastObject, id);
                     if (!lastNode) {
                         if (value == null) {
                             //create it
                     Object index = indexedNode.getIndex();
 
                     lastProperty = index;
-                    lastObject = reflectionProvider.getValue(id, ognlContext, lastObject);
+                    PropertyAccessor accessor = getPropertyAccessor(lastObject);
+                    lastObject = accessor.getProperty(ognlContext, lastObject, id);
+
+                    //create the lastObject
+                    if (lastObject == null) {
+                        //create it
+                        lastObject = create(ognlContext, action, id);
+                    }
+                } else if (node instanceof CollectionNode) {
+                    //A(B)
+                    CollectionNode indexedNode = (CollectionNode) node;
+                    String id = indexedNode.getIdentifier();
+                    Object index = indexedNode.getIndex();
+
+                    lastProperty = index;
+                    PropertyAccessor accessor = getPropertyAccessor(lastObject);
+                    lastObject = accessor.getProperty(ognlContext, lastObject, id);
 
                     //create the lastObject
                     if (lastObject == null) {
 
             PropertyAccessor accessor = getPropertyAccessor(lastObject);
             accessor.setProperty(ognlContext, lastObject, lastProperty, paramValue);
-        } else
-            throw new ParseException("Parameter name cannot be empty");
+        } catch (Throwable e) {
+            throw new RuntimeException(e);
+        }
     }
 
     protected PropertyAccessor getPropertyAccessor(Object object) {
+        if (object instanceof CompoundRoot)
+            return container.getInstance(PropertyAccessor.class, CompoundRoot.class.getName());
         if (object instanceof Map)
             return container.getInstance(PropertyAccessor.class, Map.class.getName());
         else if (object instanceof List)
             return container.getInstance(PropertyAccessor.class, List.class.getName());
         else if (object instanceof Collection)
             return container.getInstance(PropertyAccessor.class, Collection.class.getName());
+        else if (object instanceof Enumeration)
+            return container.getInstance(PropertyAccessor.class, Enumeration.class.getName());
+        else if (object instanceof Iterator)
+            return container.getInstance(PropertyAccessor.class, Iterator.class.getName());
         else
             return container.getInstance(PropertyAccessor.class, Object.class.getName());
 

core/src/test/java/com/opensymphony/xwork2/SimpleAction.java

     private Map<String,String> protectedMap = new HashMap<String,String>();
     private Map<String,String> existingMap = new HashMap<String,String>();
     private Map<String,String> someMap;
+    private String[] stringArray = new String[5];
+    private int[] intArray = new int[5];
+    private Collection<SimpleAction> someCollection = new ArrayList<SimpleAction>();
 
     public static boolean resultCalled;
-
+    private SimpleAction nestedAction;
 
     public SimpleAction() {
         resultCalled = false;
         existingMap.put("existingKey", "value");
     }
 
+    public Collection<SimpleAction> getSomeCollection() {
+        return someCollection;
+    }
+
+    public void setSomeCollection(Collection<SimpleAction> someCollection) {
+        this.someCollection = someCollection;
+    }
+
+    public SimpleAction getNestedAction() {
+        return nestedAction;
+    }
+
+    public void setNestedAction(SimpleAction nestedAction) {
+        this.nestedAction = nestedAction;
+    }
+
+    public String[] getStringArray() {
+        return stringArray;
+    }
+
+    public void setStringArray(String[] stringArray) {
+        this.stringArray = stringArray;
+    }
+
+    public int[] getIntArray() {
+        return intArray;
+    }
+
+    public void setIntArray(int[] intArray) {
+        this.intArray = intArray;
+    }
+
     public Map<String, String> getSomeMap() {
         return someMap;
     }

core/src/test/java/com/opensymphony/xwork2/interceptor/ParametersBinderInterceptorTest.java

+/*
+ * Copyright (c) 2002-2006 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.xwork2.interceptor;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import ognl.PropertyAccessor;
+
+import com.opensymphony.xwork2.Action;
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.ActionProxy;
+import com.opensymphony.xwork2.ModelDrivenAction;
+import com.opensymphony.xwork2.SimpleAction;
+import com.opensymphony.xwork2.TestBean;
+import com.opensymphony.xwork2.TextProvider;
+import com.opensymphony.xwork2.XWorkTestCase;
+import com.opensymphony.xwork2.config.entities.ActionConfig;
+import com.opensymphony.xwork2.config.providers.MockConfigurationProvider;
+import com.opensymphony.xwork2.config.providers.XmlConfigurationProvider;
+import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
+import com.opensymphony.xwork2.mock.MockActionInvocation;
+import com.opensymphony.xwork2.ognl.OgnlValueStack;
+import com.opensymphony.xwork2.ognl.OgnlValueStackFactory;
+import com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor;
+import com.opensymphony.xwork2.util.CompoundRoot;
+import com.opensymphony.xwork2.util.ValueStack;
+import com.opensymphony.xwork2.util.ValueStackFactory;
+
+
+/**
+ * Unit test for {@link ParametersInterceptor}.
+ *
+ * @author Jason Carreira
+ */
+public class ParametersBinderInterceptorTest extends XWorkTestCase {
+
+    public void testDoesNotAllowMethodInvocations() throws Exception {
+        Map<String, Object> params = new HashMap<String, Object>();
+        params.put("@java.lang.System@exit(1).dummy", "dumb value");
+
+        HashMap<String, Object> extraContext = new HashMap<String, Object>();
+        extraContext.put(ActionContext.PARAMETERS, params);
+
+        ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.MODEL_DRIVEN_PARAM_TEST, extraContext);
+        assertEquals(Action.SUCCESS, proxy.execute());
+
+        ModelDrivenAction action = (ModelDrivenAction) proxy.getAction();
+        TestBean model = (TestBean) action.getModel();
+
+        String property = System.getProperty("xwork.security.test");
+        assertNull(property);
+    }
+
+    public void testModelDrivenParameters() throws Exception {
+        Map<String, Object> params = new HashMap<String, Object>();
+        final String fooVal = "com.opensymphony.xwork2.interceptor.ParametersInterceptorTest.foo";
+        params.put("foo", fooVal);
+
+        final String nameVal = "com.opensymphony.xwork2.interceptor.ParametersInterceptorTest.name";
+        params.put("name", nameVal);
+        params.put("count", "15");
+
+        HashMap<String, Object> extraContext = new HashMap<String, Object>();
+        extraContext.put(ActionContext.PARAMETERS, params);
+
+        ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.MODEL_DRIVEN_PARAM_TEST, extraContext);
+        assertEquals(Action.SUCCESS, proxy.execute());
+
+        ModelDrivenAction action = (ModelDrivenAction) proxy.getAction();
+        TestBean model = (TestBean) action.getModel();
+        assertEquals(nameVal, model.getName());
+        assertEquals(15, model.getCount());
+        assertEquals(fooVal, action.getFoo());
+    }
+
+    public void testParametersDoesNotAffectSession() throws Exception {
+        Map<String, Object> params = new HashMap<String, Object>();
+        params.put("blah", "This is blah");
+        params.put("#session.foo", "Foo");
+        params.put("\u0023session[\'user\']", "0wn3d");
+        params.put("\\u0023session[\'user\']", "0wn3d");
+        params.put("\u0023session.user2", "0wn3d");
+        params.put("\\u0023session.user2", "0wn3d");
+        params.put("('\u0023'%20%2b%20'session[\'user3\']')(unused)", "0wn3d");
+        params.put("('\\u0023' + 'session[\\'user4\\']')(unused)", "0wn3d");
+        params.put("('\u0023'%2b'session[\'user5\']')(unused)", "0wn3d");
+        params.put("('\\u0023'%2b'session[\'user5\']')(unused)", "0wn3d");
+
+        HashMap<String, Object> extraContext = new HashMap<String, Object>();
+        extraContext.put(ActionContext.PARAMETERS, params);
+
+        ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME, extraContext);
+        ValueStack stack = proxy.getInvocation().getStack();
+        HashMap<String, Object> session = new HashMap<String, Object>();
+        stack.getContext().put("session", session);
+        proxy.execute();
+        assertEquals("This is blah", ((SimpleAction) proxy.getAction()).getBlah());
+        assertNull(session.get("foo"));
+        assertNull(session.get("user"));
+        assertNull(session.get("user2"));
+        assertNull(session.get("user3"));
+        assertNull(session.get("user4"));
+        assertNull(session.get("user5"));
+    }
+
+    public void testParameters() throws Exception {
+        Map<String, Object> params = new HashMap<String, Object>();
+        params.put("blah", "This is blah");
+
+        HashMap<String, Object> extraContext = new HashMap<String, Object>();
+        extraContext.put(ActionContext.PARAMETERS, params);
+
+        ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME, extraContext);
+        proxy.execute();
+        assertEquals("This is blah", ((SimpleAction) proxy.getAction()).getBlah());
+    }
+
+     public void testParametersWithSpacesInTheName() throws Exception {
+        Map<String, Object> params = new HashMap<String, Object>();
+        params.put("theProtectedMap['p0 p1']", "test1");
+        params.put("theProtectedMap['p0p1 ']", "test2");
+        params.put("theProtectedMap[' p0p1 ']", "test3");
+        params.put("theProtectedMap[' p0 p1 ']", "test4");
+
+        HashMap<String, Object> extraContext = new HashMap<String, Object>();
+        extraContext.put(ActionContext.PARAMETERS, params);
+
+        ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME, extraContext);
+        proxy.execute();
+        Map<String, String> existingMap =  ((SimpleAction) proxy.getAction()).getTheProtectedMap();
+        assertEquals(4, existingMap.size());
+        assertEquals("test1", existingMap.get("p0 p1"));
+        assertEquals("test2", existingMap.get("p0p1 "));
+        assertEquals("test3", existingMap.get(" p0p1 "));
+        assertEquals("test4", existingMap.get(" p0 p1 "));
+    }
+
+    public void testExcludedTrickyParameters() throws Exception {
+        Map<String, Object> params = new HashMap<String, Object>() {
+            {
+                put("blah", "This is blah");
+                put("name", "try_1");
+                put("(name)", "try_2");
+                put("['name']", "try_3");
+                put("['na' + 'me']", "try_4");
+                put("{name}[0]", "try_5");
+                put("(new string{'name'})[0]", "try_6");
+                put("#{key: 'name'}.key", "try_7");
+
+            }
+        };
+
+        HashMap<String, Object> extraContext = new HashMap<String, Object>();
+        extraContext.put(ActionContext.PARAMETERS, params);
+
+        ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME, extraContext);
+
+        ActionConfig config = configuration.getRuntimeConfiguration().getActionConfig("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME);
+        ParametersInterceptor pi =(ParametersInterceptor) config.getInterceptors().get(0).getInterceptor();
+        pi.setExcludeParams("name");
+
+        proxy.execute();
+
+        SimpleAction action = (SimpleAction) proxy.getAction();
+        assertNull(action.getName());
+        assertEquals("This is blah", (action).getBlah());
+    }
+
+    public void testAcceptedTrickyParameters() throws Exception {
+        Map<String, Object> params = new HashMap<String, Object>() {
+            {
+                put("blah", "This is blah");
+                put("['baz']", "123");
+                put("name", "try_1");
+                put("(name)", "try_2");
+                put("['name']", "try_3");
+                put("['na' + 'me']", "try_4");
+                put("{name}[0]", "try_5");
+                put("(new string{'name'})[0]", "try_6");
+                put("#{key: 'name'}.key", "try_7");
+            }
+        };
+
+        HashMap<String, Object> extraContext = new HashMap<String, Object>();
+        extraContext.put(ActionContext.PARAMETERS, params);
+
+        ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME, extraContext);
+
+        ActionConfig config = configuration.getRuntimeConfiguration().getActionConfig("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME);
+        ParametersInterceptor pi =(ParametersInterceptor) config.getInterceptors().get(0).getInterceptor();
+        pi.setAcceptParamNames("blah, baz");
+
+        proxy.execute();
+
+        SimpleAction action = (SimpleAction) proxy.getAction();
+        assertNull(action.getName());
+        assertEquals("This is blah", (action).getBlah());
+        assertEquals(123, action.getBaz());
+    }
+
+
+    public void testParametersNotAccessPrivateVariables() throws Exception {
+        Map<String, Object> params = new HashMap<String, Object>();
+        params.put("protectedMap.foo", "This is blah");
+        params.put("theProtectedMap.boo", "This is blah");
+
+        HashMap<String, Object> extraContext = new HashMap<String, Object>();
+        extraContext.put(ActionContext.PARAMETERS, params);
+
+        ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME, extraContext);
+        proxy.execute();
+        SimpleAction action = (SimpleAction) proxy.getAction();
+        assertEquals(1, action.getTheProtectedMap().size());
+        assertNotNull(action.getTheProtectedMap().get("boo"));
+        assertNull(action.getTheProtectedMap().get("foo"));
+    }
+
+    public void testParametersNotAccessProtectedMethods() throws Exception {
+        Map<String, Object> params = new HashMap<String, Object>();
+        params.put("theSemiProtectedMap.foo", "This is blah");
+        params.put("theProtectedMap.boo", "This is blah");
+
+        HashMap<String, Object> extraContext = new HashMap<String, Object>();
+        extraContext.put(ActionContext.PARAMETERS, params);
+
+        ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME, extraContext);
+        proxy.execute();
+        SimpleAction action = (SimpleAction) proxy.getAction();
+        assertEquals(1, action.getTheProtectedMap().size());
+        assertNotNull(action.getTheProtectedMap().get("boo"));
+        assertNull(action.getTheProtectedMap().get("foo"));
+    }
+
+    public void testParametersOverwriteField() throws Exception {
+        Map<String, Object> params = new LinkedHashMap<String, Object>();
+        params.put("existingMap.boo", "This is blah");
+
+        HashMap<String, Object> extraContext = new HashMap<String, Object>();
+        extraContext.put(ActionContext.PARAMETERS, params);
+
+        ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME, extraContext);
+        proxy.execute();
+        SimpleAction action = (SimpleAction) proxy.getAction();
+        assertEquals(1, action.getTheExistingMap().size());
+        assertNotNull(action.getTheExistingMap().get("boo"));
+        assertNull(action.getTheExistingMap().get("existingKey"));
+    }
+
+    public void testNonexistentParametersGetLoggedInDevMode() throws Exception {
+        loadConfigurationProviders(new XmlConfigurationProvider("xwork-test-beans.xml"),
+                new MockConfigurationProvider(Collections.singletonMap("devMode", "true")));
+        Map<String, Object> params = new HashMap<String, Object>();
+        params.put("not_a_property", "There is no action property named like this");
+
+        HashMap<String, Object> extraContext = new HashMap<String, Object>();
+        extraContext.put(ActionContext.PARAMETERS, params);
+        ParametersInterceptor.setDevMode("true");
+
+        ActionConfig config = configuration.getRuntimeConfiguration().getActionConfig("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME);
+        container.inject(config.getInterceptors().get(0).getInterceptor());
+        ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME, extraContext);
+        proxy.execute();
+        final String actionMessage = "" + ((SimpleAction) proxy.getAction()).getActionMessages().toArray()[0];
+        assertTrue(actionMessage.contains("Error setting expression 'not_a_property' with value 'There is no action property named like this'"));
+    }
+
+    public void testNonexistentParametersAreIgnoredInProductionMode() throws Exception {
+        loadConfigurationProviders(new XmlConfigurationProvider("xwork-test-beans.xml"),
+                new MockConfigurationProvider(Collections.singletonMap("devMode", "false")));
+        Map<String, Object> params = new HashMap<String, Object>();
+        params.put("not_a_property", "There is no action property named like this");
+
+        HashMap<String, Object> extraContext = new HashMap<String, Object>();
+        extraContext.put(ActionContext.PARAMETERS, params);
+
+        ActionConfig config = configuration.getRuntimeConfiguration().getActionConfig("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME);
+        container.inject(config.getInterceptors().get(0).getInterceptor());
+        ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME, extraContext);
+        proxy.execute();
+        assertTrue(((SimpleAction) proxy.getAction()).getActionMessages().isEmpty());
+    }
+
+    public void testNoParametersAction() throws Exception {
+        ParametersInterceptor interceptor = new ParametersInterceptor();
+        interceptor.init();
+
+        MockActionInvocation mai = new MockActionInvocation();
+        Action action = new NoParametersAction();
+        mai.setAction(action);
+
+        interceptor.doIntercept(mai);
+        interceptor.destroy();
+    }
+
+    public void testNoOrdered() throws Exception {
+        ParametersInterceptor pi = new ParametersInterceptor();
+        container.inject(pi);
+        final Map<String, Object> actual = new LinkedHashMap<String, Object>();
+        pi.setValueStackFactory(createValueStackFactory(actual));
+        ValueStack stack = createStubValueStack(actual);
+
+        Map<String, Object> parameters = new HashMap<String, Object>();
+        parameters.put("user.address.city", "London");
+        parameters.put("user.name", "Superman");
+
+        Action action = new SimpleAction();
+        pi.setParameters(action, stack, parameters);
+
+        assertEquals("ordered should be false by default", false, pi.isOrdered());
+        assertEquals(2, actual.size());
+        assertEquals("London", actual.get("user.address.city"));
+        assertEquals("Superman", actual.get("user.name"));
+
+        // is not ordered
+        List<Object> values = new ArrayList<Object>(actual.values());
+        assertEquals("London", values.get(0));
+        assertEquals("Superman", values.get(1));
+    }
+
+    public void testOrdered() throws Exception {
+        ParametersInterceptor pi = new ParametersInterceptor();
+        pi.setOrdered(true);
+        container.inject(pi);
+        final Map<String, Object> actual = new LinkedHashMap<String, Object>();
+        pi.setValueStackFactory(createValueStackFactory(actual));
+        ValueStack stack = createStubValueStack(actual);
+
+        Map<String, Object> parameters = new HashMap<String, Object>();
+        parameters.put("user.address.city", "London");
+        parameters.put("user.name", "Superman");
+
+        Action action = new SimpleAction();
+        pi.setParameters(action, stack, parameters);
+
+        assertEquals(true, pi.isOrdered());
+        assertEquals(2, actual.size());
+        assertEquals("London", actual.get("user.address.city"));
+        assertEquals("Superman", actual.get("user.name"));
+
+        // should be ordered so user.name should be first
+        List<Object> values = new ArrayList<Object>(actual.values());
+        assertEquals("Superman", values.get(0));
+        assertEquals("London", values.get(1));
+    }
+
+    public void testSetOrdered() throws Exception {
+        ParametersInterceptor pi = new ParametersInterceptor();
+        container.inject(pi);
+        assertEquals("ordered should be false by default", false, pi.isOrdered());
+        pi.setOrdered(true);
+        assertEquals(true, pi.isOrdered());
+    }
+
+    public void testExcludedParametersAreIgnored() throws Exception {
+        ParametersInterceptor pi = new ParametersInterceptor();
+        container.inject(pi);
+        pi.setExcludeParams("dojo\\..*");
+        final Map actual = new HashMap();
+        pi.setValueStackFactory(createValueStackFactory(actual));
+        ValueStack stack = createStubValueStack(actual);
+        container.inject(stack);
+
+        final Map<String, Object> expected = new HashMap<String, Object>() {
+            {
+                put("fooKey", "fooValue");
+            }
+        };
+
+        Map<String, Object> parameters = new HashMap<String, Object>() {
+            {
+                put("dojo.test", "dojoValue");
+                put("fooKey", "fooValue");
+            }
+        };
+        pi.setParameters(new NoParametersAction(), stack, parameters);
+        assertEquals(expected, actual);
+    }
+
+    private ValueStackFactory createValueStackFactory(final Map<String, Object> context) {
+        OgnlValueStackFactory factory = new OgnlValueStackFactory() {
+            @Override
+            public ValueStack createValueStack(ValueStack stack) {
+                return createStubValueStack(context);
+            }
+        };
+        container.inject(factory);
+        return factory;
+    }
+
+    private ValueStack createStubValueStack(final Map<String, Object> actual) {
+        ValueStack stack = new OgnlValueStack(
+                container.getInstance(XWorkConverter.class),
+                (CompoundRootAccessor)container.getInstance(PropertyAccessor.class, CompoundRoot.class.getName()),
+                container.getInstance(TextProvider.class, "system"), true) {
+            @Override
+            public void setValue(String expr, Object value) {
+                actual.put(expr, value);
+            }
+        };
+        container.inject(stack);
+        return stack;
+    }
+
+    /*
+    public void testIndexedParameters() throws Exception {
+        Map params = new HashMap();
+        params.put("indexedProp[33]", "This is blah");
+
+        HashMap extraContext = new HashMap();
+        extraContext.put(ActionContext.PARAMETERS, params);
+
+        ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME, extraContext);
+        proxy.execute();
+        assertEquals("This is blah", ((SimpleAction) proxy.getAction()).getIndexedProp(33));
+    }
+    */
+
+
+    private class NoParametersAction implements Action, NoParameters {
+
+        public String execute() throws Exception {
+            return SUCCESS;
+        }
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        Map<String, String> params = new HashMap<String, String>();
+        params.put("enableSimpleParametersBinder", "true");
+
+        loadConfigurationProviders(new XmlConfigurationProvider("xwork-test-beans.xml"), new MockConfigurationProvider(params));
+
+        ActionConfig config = configuration.getRuntimeConfiguration().getActionConfig("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME);
+        ParametersInterceptor interceptor = (ParametersInterceptor) config.getInterceptors().get(0).getInterceptor();
+        container.inject(interceptor);
+    }
+}

core/src/test/java/com/opensymphony/xwork2/parameters/XWorkParametersBinderTest.java

         assertEquals("Lex Luthor", action.getName());
     }
 
-    public void testNestedNotNull() throws ParseException, OgnlException {
+    public void testNested() throws ParseException, OgnlException {
         String expr = "bean.name";
         SimpleAction action = new SimpleAction();
 
 
     //Lists
     public void testSimpleList() throws ParseException, OgnlException {
-           String expr = "someList[0]";
-           SimpleAction action = new SimpleAction();
+        String expr = "someList[0]";
+        SimpleAction action = new SimpleAction();
+
+        assertEquals(0, action.getSomeList().size());
+
+        Map<String, Object> context = new HashMap<String, Object>();
+        binder.setProperty(context, action, expr, "Lex Luthor");
+
+        assertEquals("Lex Luthor", action.getSomeList().get(0));
+    }
+
+    public void testSimpleListNull() throws ParseException, OgnlException {
+        String expr = "someList[0]";
+        SimpleAction action = new SimpleAction();
+        action.setSomeList(null);
+
+        assertNull(action.getSomeList());
+
+        Map<String, Object> context = new HashMap<String, Object>();
+        binder.setProperty(context, action, expr, "Lex Luthor");
+
+        assertEquals("Lex Luthor", action.getSomeList().get(0));
+    }
+
+    public void testSimpleListNullRandomIndex() throws ParseException, OgnlException {
+        String expr = "someList[15]";
+        SimpleAction action = new SimpleAction();
+        action.setSomeList(null);
 
-           assertEquals(0, action.getSomeList().size());
+        assertNull(action.getSomeList());
 
-           Map<String, Object> context = new HashMap<String, Object>();
-           binder.setProperty(context, action, expr, "Lex Luthor");
+        Map<String, Object> context = new HashMap<String, Object>();
+        binder.setProperty(context, action, expr, "Lex Luthor");
 
-           assertEquals("Lex Luthor", action.getSomeList().get(0));
-       }
+        assertEquals("Lex Luthor", action.getSomeList().get(15));
+    }
+
+    public void testNestedNull2() throws ParseException, OgnlException {
+        String expr = "nestedAction.bean.name";
+        SimpleAction action = new SimpleAction();
+        action.setNestedAction(null);
 
+        assertNull(action.getNestedAction());
 
+        Map<String, Object> context = new HashMap<String, Object>();
+        binder.setProperty(context, action, expr, "Lex Luthor");
+
+        assertEquals("Lex Luthor", action.getNestedAction().getBean().getName());
+    }
+
+    public void testNestedNull3() throws ParseException, OgnlException {
+        String expr = "nestedAction.nestedAction.bean.name";
+        SimpleAction action = new SimpleAction();
+        action.setNestedAction(null);
+
+        assertNull(action.getNestedAction());
+
+        Map<String, Object> context = new HashMap<String, Object>();
+        binder.setProperty(context, action, expr, "Lex Luthor");
+
+        assertEquals("Lex Luthor", action.getNestedAction().getBean().getName());
+    }
 
     @Override
     protected void setUp() throws Exception {
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.