Anonymous avatar Anonymous committed a169a0e

Fixing not short-circuiting for nested visited validations
XW-588

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

Comments (0)

Files changed (3)

src/java/com/opensymphony/xwork2/validator/DefaultActionValidatorManager.java

 
 import com.opensymphony.xwork2.ObjectFactory;
 import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.validator.validators.VisitorFieldValidator;
 import com.opensymphony.xwork2.inject.Inject;
 import com.opensymphony.xwork2.util.FileManager;
 import com.opensymphony.xwork2.util.ValueStack;
                     fValidator = (FieldValidator) validator;
                     fullFieldName = fValidator.getValidatorContext().getFullFieldName(fValidator.getFieldName());
 
+                    // This is pretty crap, but needed to support short-circuited validations on nested visited objects
+                    if (validatorContext instanceof VisitorFieldValidator.AppendingValidatorContext) {
+                        VisitorFieldValidator.AppendingValidatorContext appendingValidatorContext =
+                                (VisitorFieldValidator.AppendingValidatorContext) validatorContext;
+                        fullFieldName = appendingValidatorContext.getFullFieldNameFromParent(fValidator.getFieldName());
+                    }
+
                     if ((shortcircuitedFields != null) && shortcircuitedFields.contains(fullFieldName)) {
                         if (LOG.isDebugEnabled()) {
                             LOG.debug("Short-circuited, skipping");

src/java/com/opensymphony/xwork2/validator/validators/VisitorFieldValidator.java

     }
 
 
-    private class AppendingValidatorContext extends DelegatingValidatorContext {
-        Object o;
-        String field;
-        String message;
+    public static class AppendingValidatorContext extends DelegatingValidatorContext {
+        private String field;
+        private String message;
         private ValidatorContext parent;
 
         public AppendingValidatorContext(ValidatorContext parent, Object object, String field, String message) {
          * @return field name in OGNL syntax
          */
         public String getFullFieldName(String fieldName) {
-            if (parent instanceof AppendingValidatorContext) {
-                return parent.getFullFieldName("") + field + "." + fieldName;
-            }
+//            if (parent instanceof AppendingValidatorContext) {
+//                return parent.getFullFieldName("") + field + "." + fieldName;
+//            }
             return field + "." + fieldName;
         }
 
+        public String getFullFieldNameFromParent(String fieldName) {
+            return parent.getFullFieldName(field+"."+fieldName);
+        }
+
         public void addActionError(String anErrorMessage) {
             super.addFieldError(getFullFieldName(field), message + anErrorMessage);
         }

src/test/com/opensymphony/xwork2/validator/ActionValidatorManagerTest.java

+package com.opensymphony.xwork.validator;
+
+import com.opensymphony.xwork2.ActionSupport;
+import com.opensymphony.xwork2.XWorkTestCase;
+import com.opensymphony.xwork2.util.ValueStack;
+import com.opensymphony.xwork2.util.ValueStackFactory;
+import com.opensymphony.xwork2.validator.validators.FieldExpressionValidator;
+import com.opensymphony.xwork2.validator.validators.RequiredFieldValidator;
+import com.opensymphony.xwork2.validator.validators.RequiredStringValidator;
+import com.opensymphony.xwork2.validator.validators.VisitorFieldValidator;
+import com.opensymphony.xwork2.validator.DefaultActionValidatorManager;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * A test case for ActionValidatorManager.
+ *
+ * @author tmjee
+ * @version $Date$ $Id$
+ */
+public class ActionValidatorManagerTest extends XWorkTestCase {
+
+
+
+    public void testValidate() throws Exception {
+        /* MockAction.class */
+        // reference number
+        ValueStack stack = container.getInstance(ValueStackFactory.class).createValueStack();
+        final RequiredStringValidator referenceNumberRequiredStringValidator = new RequiredStringValidator();
+        referenceNumberRequiredStringValidator.setFieldName("referenceNumber");
+        referenceNumberRequiredStringValidator.setDefaultMessage("Reference number is required");
+        referenceNumberRequiredStringValidator.setValueStack(stack);
+
+        // order
+        final RequiredFieldValidator orderRequiredValidator = new RequiredFieldValidator();
+        orderRequiredValidator.setFieldName("order");
+        orderRequiredValidator.setDefaultMessage("Order is required");
+        orderRequiredValidator.setValueStack(stack);
+
+        // customer
+        final RequiredFieldValidator customerRequiredValidator = new RequiredFieldValidator();
+        customerRequiredValidator.setFieldName("customer");
+        customerRequiredValidator.setDefaultMessage("Customer is required");
+        customerRequiredValidator.setValueStack(stack);
+        final VisitorFieldValidator customerVisitorValidator = new VisitorFieldValidator();
+        customerVisitorValidator.setAppendPrefix(true);
+        customerVisitorValidator.setFieldName("customer");
+        customerVisitorValidator.setValueStack(stack);
+
+        /* Customer.class */
+        // customer -> name
+        final RequiredStringValidator customerNameRequiredStringValidator = new RequiredStringValidator();
+        customerNameRequiredStringValidator.setFieldName("name");
+        customerNameRequiredStringValidator.setDefaultMessage("Name is required");
+        customerNameRequiredStringValidator.setValueStack(stack);
+
+        // customer -> age
+        final RequiredFieldValidator customerAgeRequiredValidator = new RequiredFieldValidator();
+        customerAgeRequiredValidator.setFieldName("age");
+        customerAgeRequiredValidator.setDefaultMessage("Age is required");
+        customerAgeRequiredValidator.setValueStack(stack);
+
+        // customer -> Address
+        final RequiredFieldValidator customerAddressRequiredFieldValidator = new RequiredFieldValidator();
+        customerAddressRequiredFieldValidator.setFieldName("address");
+        customerAddressRequiredFieldValidator.setDefaultMessage("Address is required");
+        customerAddressRequiredFieldValidator.setValueStack(stack);
+
+        final VisitorFieldValidator customerAddressVisitorFieldValidator = new VisitorFieldValidator();
+        customerAddressVisitorFieldValidator.setFieldName("address");
+        customerAddressVisitorFieldValidator.setAppendPrefix(true);
+        //customerAddressVisitorFieldValidator.setDefaultMessage("");
+        customerAddressVisitorFieldValidator.setValueStack(stack);
+
+
+
+        /* Address.class */
+        // customer -> Address -> street
+        final RequiredStringValidator customerAddressStreetRequiredFieldValidator = new RequiredStringValidator();
+        customerAddressStreetRequiredFieldValidator.setFieldName("street");
+        customerAddressStreetRequiredFieldValidator.setDefaultMessage("Street is required");
+        customerAddressStreetRequiredFieldValidator.setShortCircuit(true);
+        customerAddressStreetRequiredFieldValidator.setValueStack(stack);
+
+        final RequiredStringValidator customerAddressStreetRequiredFieldValidator2 = new RequiredStringValidator();
+        customerAddressStreetRequiredFieldValidator2.setFieldName("street");
+        customerAddressStreetRequiredFieldValidator2.setDefaultMessage("Street is required 2");
+        customerAddressStreetRequiredFieldValidator2.setShortCircuit(true);
+        customerAddressStreetRequiredFieldValidator2.setValueStack(stack);
+
+        // customer -> Address -> pobox
+        final RequiredStringValidator customerAddressPoboxRequiredFieldValidator = new RequiredStringValidator();
+        customerAddressPoboxRequiredFieldValidator.setFieldName("pobox");
+        customerAddressPoboxRequiredFieldValidator.setDefaultMessage("PO Box is required");
+        customerAddressPoboxRequiredFieldValidator.setShortCircuit(false);
+        customerAddressPoboxRequiredFieldValidator.setValueStack(stack);
+
+        final RequiredStringValidator customerAddressPoboxRequiredFieldValidator2 = new RequiredStringValidator();
+        customerAddressPoboxRequiredFieldValidator2.setFieldName("pobox");
+        customerAddressPoboxRequiredFieldValidator2.setDefaultMessage("PO Box is required 2");
+        customerAddressPoboxRequiredFieldValidator2.setShortCircuit(false);
+        customerAddressPoboxRequiredFieldValidator2.setValueStack(stack);
+
+
+
+        final List validatorsForMockAction = new ArrayList() {
+            {
+                add(referenceNumberRequiredStringValidator);
+                add(orderRequiredValidator);
+                add(customerRequiredValidator);
+                add(customerVisitorValidator);
+            }
+        };
+
+        final List validatorsForCustomer = new ArrayList() {
+            {
+                add(customerNameRequiredStringValidator);
+                add(customerAgeRequiredValidator);
+                add(customerAddressRequiredFieldValidator);
+                add(customerAddressVisitorFieldValidator);
+            }
+        };
+
+        final List validatorsForAddress = new ArrayList() {
+            {
+                add(customerAddressStreetRequiredFieldValidator);
+                add(customerAddressStreetRequiredFieldValidator2);
+                add(customerAddressPoboxRequiredFieldValidator);
+                add(customerAddressPoboxRequiredFieldValidator2);
+            }
+        };
+
+
+        DefaultActionValidatorManager validatorManager = new DefaultActionValidatorManager() {
+            @Override
+            public List getValidators(Class clazz, String context, String method) {
+                if (clazz.isAssignableFrom(MockAction.class)) {
+                    return validatorsForMockAction;
+                }
+                else if (clazz.isAssignableFrom(Customer.class)) {
+                    return validatorsForCustomer;
+                }
+                else if (clazz.isAssignableFrom(Address.class)) {
+                    return validatorsForAddress;
+                }
+                return Collections.EMPTY_LIST;
+            }
+        };
+        customerVisitorValidator.setActionValidatorManager(validatorManager);
+        customerAddressVisitorFieldValidator.setActionValidatorManager(validatorManager);
+
+        MockAction action = new MockAction();
+        stack.push(action);
+        validatorManager.validate(action, "ctx");
+
+        assertFalse(action.hasActionErrors());
+        assertFalse(action.hasActionMessages());
+        assertTrue(action.hasFieldErrors());
+        assertTrue(action.getFieldErrors().containsKey("referenceNumber"));
+        assertEquals(((List)action.getFieldErrors().get("referenceNumber")).size(), 1);
+        assertTrue(action.getFieldErrors().containsKey("order"));
+        assertEquals(((List)action.getFieldErrors().get("order")).size(), 1);
+        assertTrue(action.getFieldErrors().containsKey("customer.name"));
+        assertEquals(((List)action.getFieldErrors().get("customer.name")).size(), 1);
+        assertTrue(action.getFieldErrors().containsKey("customer.age"));
+        assertEquals(((List)action.getFieldErrors().get("customer.age")).size(), 1);
+        assertTrue(action.getFieldErrors().containsKey("customer.address.street"));
+        assertEquals(((List)action.getFieldErrors().get("customer.address.street")).size(), 1);
+        assertTrue(action.getFieldErrors().containsKey("customer.address.pobox"));
+        //assertEquals(((List)action.getFieldErrors().get("customer.address.pobox")).size(), 2);
+
+        for (Iterator i = action.getFieldErrors().keySet().iterator(); i.hasNext(); ) {
+            System.out.println(i.next());
+        }
+
+
+        for (Iterator i = ((List)action.getFieldErrors().get("customer.address.street")).iterator(); i.hasNext();) {
+            System.out.println("**"+i.next());
+        }
+        for (Iterator i = ((List)action.getFieldErrors().get("customer.address.pobox")).iterator(); i.hasNext();) {
+            System.out.println("**"+i.next());
+        }
+
+    }
+
+    private class MockAction extends ActionSupport {
+
+        private String referenceNumber;
+        private Integer order;
+        private Customer customer = new Customer();
+
+
+        public String getReferenceNumber() { return referenceNumber; }
+        public void setReferenceNumber(String referenceNumber) { this.referenceNumber = referenceNumber; }
+
+        public Integer getOrder() { return order; }
+        public void setOrder(Integer order) { this.order = order; }
+
+        public Customer getCustomer() { return customer; }
+        public void setCustomer(Customer customer) { this.customer = customer; }
+    }
+
+
+    private class Customer {
+        private String name;
+        private Integer age;
+        private Address address = new Address();
+
+        public String getName() { return name; }
+        public void setName(String name) { this.name = name; }
+
+        public Integer getAge() { return age; }
+        public void setAge(Integer age) { this.age = age; }
+
+        public Address getAddress() { return address; }
+        public void setAddress(Address address) { this.address = address; }
+    }
+
+    private class Address {
+        private String street;
+        private String pobox;
+
+        public String getStreet() { return street; }
+        public void setStreet(String street) { this.street = street; }
+
+        public String getPobox() { return pobox; }
+        public void setPobox(String pobox) { this.pobox = pobox; }
+    }
+}
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.