Commits

Anonymous committed e846ea6

XW-75: validations can now be run against sub-properties of object properties held by the Action using Ognl notation.

git-svn-id: http://svn.opensymphony.com/svn/xwork/trunk@31e221344d-f017-0410-9bd5-d282ab1896d7

Comments (0)

Files changed (5)

src/java/com/opensymphony/xwork/validator/validators/ValidatorSupport.java

 package com.opensymphony.xwork.validator.validators;
 
 import com.opensymphony.xwork.ActionContext;
+import com.opensymphony.xwork.util.OgnlUtil;
 import com.opensymphony.xwork.util.OgnlValueStack;
 import com.opensymphony.xwork.util.TextParseUtil;
 import com.opensymphony.xwork.validator.ValidationException;
 
     protected Object getFieldValue(String name, Object object) throws ValidationException {
         try {
-            return Ognl.getValue(name, object);
+            return Ognl.getValue(OgnlUtil.compile(name), Ognl.createDefaultContext(object), object);
         } catch (OgnlException e) {
             final String msg = "Caught exception while getting value for field " + name;
             log.error(msg, e);

src/test/com/opensymphony/xwork/SimpleAction-subproperty-validation.xml

+<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0//EN" "http://www.opensymphony.com/xwork/xwork-validator-1.0.dtd">
+<validators>
+    <field name="bean.name">
+        <field-validator type="required">
+            <message>You must enter a name for the bean.</message>
+        </field-validator>
+    </field>
+    <field name="bean.count">
+        <field-validator type="required">
+            <message>You must have a count for the bean.</message>
+        </field-validator>
+        <field-validator type="int">
+            <param name="min">0</param>
+            <param name="max">10</param>
+            <message>bean.count out of range.</message>
+        </field-validator>
+    </field>
+</validators>

src/test/com/opensymphony/xwork/SimpleAction.java

     private Properties settings = new Properties();
     private String blah;
     private String name;
+    private TestBean bean = new TestBean();
     private int bar;
     private int baz;
     private int foo;
         return baz;
     }
 
+    public void setBean(TestBean bean) {
+        this.bean = bean;
+    }
+
+    public TestBean getBean() {
+        return bean;
+    }
+
     public void setBlah(String blah) {
         this.blah = blah;
     }

src/test/com/opensymphony/xwork/config/providers/MockConfigurationProvider.java

     public static final String PARAM_INTERCEPTOR_ACTION_NAME = "parametersInterceptorTest";
     public static final String VALIDATION_ACTION_NAME = "validationInterceptorTest";
     public static final String VALIDATION_ALIAS_NAME = "validationAlias";
+    public static final String VALIDATION_SUBPROPERTY_NAME = "subproperty";
 
     //~ Methods ////////////////////////////////////////////////////////////////
 
         ActionConfig validationActionConfig = new ActionConfig(null, SimpleAction.class, null, results, interceptors);
         defaultPackageContext.addActionConfig(VALIDATION_ACTION_NAME, validationActionConfig);
         defaultPackageContext.addActionConfig(VALIDATION_ALIAS_NAME, validationActionConfig);
+        defaultPackageContext.addActionConfig(VALIDATION_SUBPROPERTY_NAME, validationActionConfig);
 
         // We need this actionconfig to be the final destination for action chaining
         ActionConfig barActionConfig = new ActionConfig(null, SimpleAction.class, null, null, null);

src/test/com/opensymphony/xwork/validator/SimpleActionValidationTest.java

     }
 
     public void testParamterizedMessage() {
-        ConfigurationManager.addConfigurationProvider(new MockConfigurationProvider());
-
         HashMap params = new HashMap();
         params.put("bar", "42");
 
         }
     }
 
+    public void testSubPropertiesAreValidated() {
+        HashMap params = new HashMap();
+        params.put("baz", "10");
+
+        //valid values
+        params.put("foo", "8");
+        params.put("bar", "7");
+        params.put("date", "12/23/2002");
+
+        params.put("bean.name", "Name should be valid");
+
+        // this should cause a message
+        params.put("bean.count", "100");
+
+        HashMap extraContext = new HashMap();
+        extraContext.put(ActionContext.PARAMETERS, params);
+
+        try {
+            ActionProxy proxy = ActionProxyFactory.getFactory().createActionProxy("", MockConfigurationProvider.VALIDATION_SUBPROPERTY_NAME, extraContext);
+            proxy.execute();
+            assertTrue(((ValidationAware) proxy.getAction()).hasFieldErrors());
+
+            Map errors = ((ValidationAware) proxy.getAction()).getFieldErrors();
+            List beanCountErrors = (List) errors.get("bean.count");
+            assertEquals(1, beanCountErrors.size());
+
+            String errorMessage = (String) beanCountErrors.get(0);
+            assertNotNull(errorMessage);
+            assertEquals("bean.count out of range.", errorMessage);
+        } catch (Exception e) {
+            e.printStackTrace();
+            fail();
+        }
+    }
+
     protected void setUp() throws Exception {
         ConfigurationManager.clearConfigurationProviders();
         ConfigurationManager.addConfigurationProvider(new MockConfigurationProvider());
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.