Hi, 
we are starting to use tapestry-beanvalidator and found that the current 
BeanEditor implementation can't be used with complex beans (beans that contain 
other beans) for beanvalidation. 
The problem is that BeanEditor doesn't provide the correct 
BeanValidationContext to the validation framework. 

Given the following beans: 

public class ComplexBean { 
private SomeSimpleBean someSimpleBean; 
@NotNull private String simpleNotNullProperty; 
... 
} 

public class SimpleBean { 
@Min(6) private int minValue; 
.. 
} 

One would expect that the following page would validate all the constraint from 
both ComplexBean and SimpleBean: 
<t:form validate="complexBean"> 
<t:BeanEditor object="complexBean" /> 
<t:BeanEditor object="complexBean.someSimpleBean" /> 
... 

Instead only ComplexBean. simpleNotNullProperty constraint is validated. 

BeanEditor should provide the validation framework with a new 
BeanValidationContext bound to the object being validated all the times. 

Patch with test case attached. Shell I open a jira? 


Luca 

diff --git a/tapestry-beanvalidator/src/test/java/org/apache/tapestry5/beanvalidator/integration/TapestryBeanValidationIntegrationTests.java b/tapestry-beanvalidator/src/test/java/org/apache/tapestry5/beanvalidator/integration/TapestryBeanValidationIntegrationTests.java
index a986ba2..0da3733 100644
--- a/tapestry-beanvalidator/src/test/java/org/apache/tapestry5/beanvalidator/integration/TapestryBeanValidationIntegrationTests.java
+++ b/tapestry-beanvalidator/src/test/java/org/apache/tapestry5/beanvalidator/integration/TapestryBeanValidationIntegrationTests.java
@@ -202,6 +202,20 @@ public class TapestryBeanValidationIntegrationTests extends SeleniumTestCase
         assertTextPresent("Login Name size must be between 7 and 10", "Login Name must match \"[0-9]+\"");
     }
 
+    @Test
+    public void beaneditor_validation() throws Exception
+    {
+        openLinks("ComplexBean Demo");
+
+        // Test JSR-303 validator
+
+        clickAndWait(SUBMIT);
+
+        assertTextPresent("Simple Not Null Property may not be null",
+                "Min Value must be greater than or equal to 6", "Not Null String may not be null");
+
+    }
+    
     protected final void assertBubbleMessage(String fieldId, String expected)
     {
         String popupId = fieldId + "_errorpopup";
diff --git a/tapestry-beanvalidator/src/test/java/org/example/testapp/entities/ComplexBean.java b/tapestry-beanvalidator/src/test/java/org/example/testapp/entities/ComplexBean.java
new file mode 100644
index 0000000..beaa840
--- /dev/null
+++ b/tapestry-beanvalidator/src/test/java/org/example/testapp/entities/ComplexBean.java
@@ -0,0 +1,44 @@
+package org.example.testapp.entities;
+
+import javax.validation.constraints.NotNull;
+
+public class ComplexBean
+{
+
+    private SomeSimpleBean someSimpleBean;
+    private SomeOtherSimpleBean someOtherSimpleBean;
+
+    @NotNull
+    private String simpleNotNullProperty;
+
+    public SomeSimpleBean getSomeSimpleBean()
+    {
+        return someSimpleBean;
+    }
+
+    public void setSomeSimpleBean(SomeSimpleBean someSimpleBean)
+    {
+        this.someSimpleBean = someSimpleBean;
+    }
+
+    public SomeOtherSimpleBean getSomeOtherSimpleBean()
+    {
+        return someOtherSimpleBean;
+    }
+
+    public void setSomeOtherSimpleBean(SomeOtherSimpleBean someOtherSimpleBean)
+    {
+        this.someOtherSimpleBean = someOtherSimpleBean;
+    }
+
+    public String getSimpleNotNullProperty()
+    {
+        return simpleNotNullProperty;
+    }
+
+    public void setSimpleNotNullProperty(String simpleNotNullProperty)
+    {
+        this.simpleNotNullProperty = simpleNotNullProperty;
+    }
+
+}
diff --git a/tapestry-beanvalidator/src/test/java/org/example/testapp/entities/SomeOtherSimpleBean.java b/tapestry-beanvalidator/src/test/java/org/example/testapp/entities/SomeOtherSimpleBean.java
new file mode 100644
index 0000000..9a262f3
--- /dev/null
+++ b/tapestry-beanvalidator/src/test/java/org/example/testapp/entities/SomeOtherSimpleBean.java
@@ -0,0 +1,21 @@
+package org.example.testapp.entities;
+
+import javax.validation.constraints.NotNull;
+
+public class SomeOtherSimpleBean
+{
+
+    @NotNull
+    private String notNullString;
+
+    public String getNotNullString()
+    {
+        return notNullString;
+    }
+
+    public void setNotNullString(String notNullString)
+    {
+        this.notNullString = notNullString;
+    }
+
+}
diff --git a/tapestry-beanvalidator/src/test/java/org/example/testapp/entities/SomeSimpleBean.java b/tapestry-beanvalidator/src/test/java/org/example/testapp/entities/SomeSimpleBean.java
new file mode 100644
index 0000000..1564112
--- /dev/null
+++ b/tapestry-beanvalidator/src/test/java/org/example/testapp/entities/SomeSimpleBean.java
@@ -0,0 +1,21 @@
+package org.example.testapp.entities;
+
+import javax.validation.constraints.Min;
+
+public class SomeSimpleBean
+{
+
+    @Min(6)
+    private int minValue;
+
+    public int getMinValue()
+    {
+        return minValue;
+    }
+
+    public void setMinValue(int minValue)
+    {
+        this.minValue = minValue;
+    }
+
+}
diff --git a/tapestry-beanvalidator/src/test/java/org/example/testapp/pages/ComplexBeanDemo.java b/tapestry-beanvalidator/src/test/java/org/example/testapp/pages/ComplexBeanDemo.java
new file mode 100644
index 0000000..f7b2623
--- /dev/null
+++ b/tapestry-beanvalidator/src/test/java/org/example/testapp/pages/ComplexBeanDemo.java
@@ -0,0 +1,14 @@
+package org.example.testapp.pages;
+
+import org.apache.tapestry5.annotations.Persist;
+import org.apache.tapestry5.annotations.Property;
+import org.example.testapp.entities.ComplexBean;
+
+public class ComplexBeanDemo
+{
+
+    @Property
+    @Persist
+    private ComplexBean complexBean;
+
+}
diff --git a/tapestry-beanvalidator/src/test/webapp/ComplexBeanDemo.tml b/tapestry-beanvalidator/src/test/webapp/ComplexBeanDemo.tml
new file mode 100644
index 0000000..c701b1f
--- /dev/null
+++ b/tapestry-beanvalidator/src/test/webapp/ComplexBeanDemo.tml
@@ -0,0 +1,19 @@
+<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd";>
+    <body>
+        <t:form clientValidation="false" validate="complexBean">
+        	<t:errors/>
+
+        	<br/>
+        	<t:BeanEditor object="complexBean" />
+        	        	
+        	<br/>
+        	<t:BeanEditor object="complexBean.someSimpleBean" />
+        	
+        	<br/>
+        	<t:BeanEditor object="complexBean.someOtherSimpleBean" />
+        	
+        	<br/>
+        	<input type="submit" value="Go"/>
+        </t:form>
+     </body>
+</html>
\ No newline at end of file
diff --git a/tapestry-beanvalidator/src/test/webapp/Index.tml b/tapestry-beanvalidator/src/test/webapp/Index.tml
index da8978e..0970c96 100644
--- a/tapestry-beanvalidator/src/test/webapp/Index.tml
+++ b/tapestry-beanvalidator/src/test/webapp/Index.tml
@@ -24,6 +24,9 @@
             <li>
                 <t:pagelink page="OnPrepareDemo">OnPrepare Demo</t:pagelink>
             </li>
+            <li>
+                <t:pagelink page="ComplexBeanDemo">ComplexBean Demo</t:pagelink>
+            </li>            
         </ul>
     </body>
 </html>
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/BeanEditor.java b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/BeanEditor.java
index 1d7ed6c..94c37b9 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/BeanEditor.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/BeanEditor.java
@@ -166,6 +166,8 @@ public class BeanEditor
      */
     private Object cachedObject;
 
+    private BeanValidationContext originalBeanValidationContext;
+    
     // Needed for testing as well
 
     public Object getObject()
@@ -213,10 +215,6 @@ public class BeanEditor
                         PlasticUtils.toTypeName(model.getBeanType()), resources.getCompleteId(), ex);
                 throw new TapestryException(message, resources.getLocation(), ex);
             }
-
-            // If 'object' parameter is bound to a null-value BeanValidationContext is empty.
-            // This prevents JSR-303 javascript validators to be rendered properly .
-            refreshBeanValidationContext();
         }
 
         BeanEditContext context = new BeanEditContext()
@@ -235,20 +233,22 @@ public class BeanEditor
         cachedObject = object;
 
         environment.push(BeanEditContext.class, context);
+        // Always provide a new BeanValidationContext
+        originalBeanValidationContext = environment.push(BeanValidationContext.class,
+                new BeanValidationContextImpl(object));
+        
     }
 
     void cleanupEnvironment()
     {
         environment.pop(BeanEditContext.class);
-    }
-
-    private void refreshBeanValidationContext()
-    {
-        if (environment.peek(BeanValidationContext.class) != null)
+        environment.pop(BeanValidationContext.class);
+        // Restore the original BeanValidationContext as it might still be useful to the enclosing
+        // form
+        if (originalBeanValidationContext != null)
         {
-            environment.pop(BeanValidationContext.class);
-
-            environment.push(BeanValidationContext.class, new BeanValidationContextImpl(object));
+            environment.push(BeanValidationContext.class, originalBeanValidationContext);
+            originalBeanValidationContext = null;
         }
     }
 
---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org
For additional commands, e-mail: users-h...@tapestry.apache.org

Reply via email to