tapestry-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From hls...@apache.org
Subject tapestry-5 git commit: Fix bugs related to field validation inside a BeanEditor component
Date Tue, 03 Feb 2015 00:39:49 GMT
Repository: tapestry-5
Updated Branches:
  refs/heads/master ad5cca595 -> ef0d1448a


Fix bugs related to field validation inside a BeanEditor component


Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/ef0d1448
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/ef0d1448
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/ef0d1448

Branch: refs/heads/master
Commit: ef0d1448aca3bca3ed4f8aea6fbedd6b77438fcc
Parents: ad5cca5
Author: Howard M. Lewis Ship <hlship@apache.org>
Authored: Mon Feb 2 16:39:40 2015 -0800
Committer: Howard M. Lewis Ship <hlship@apache.org>
Committed: Mon Feb 2 16:39:40 2015 -0800

----------------------------------------------------------------------
 .../tapestry5/corelib/base/AbstractField.java   | 10 +++
 .../corelib/components/BeanEditor.java          | 20 +++--
 .../tapestry5/corelib/components/Form.java      |  4 +-
 .../corelib/pages/PropertyEditBlocks.java       | 83 +++++++++++++++-----
 .../internal/BeanValidationContext.java         | 22 ++++--
 .../internal/BeanValidationContextImpl.java     | 20 +++--
 6 files changed, 113 insertions(+), 46 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/ef0d1448/tapestry-core/src/main/java/org/apache/tapestry5/corelib/base/AbstractField.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/base/AbstractField.java
b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/base/AbstractField.java
index 851de73..4f977d0 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/base/AbstractField.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/base/AbstractField.java
@@ -364,6 +364,16 @@ public abstract class AbstractField implements Field2
         beanValidationContext.setCurrentProperty(null);
     }
 
+    /**
+     * The validation id is used by Tapestry to coordinate an incoming request (with input
for fields,
+     * an validation errors) with a render of the form containing a field. Normally, a validationId
is assigned
+     * on first access and persists for the remainder of the request; however the {@link
org.apache.tapestry5.corelib.components.BeanEditor}
+     * (or rather, the components used by the BeanEditor) may need to override this as the
same fields render and re-render
+     * multiple times in the same request.
+     *
+     * @since 5.4
+     */
+    @Parameter
     private String validationId;
 
     @Override

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/ef0d1448/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/BeanEditor.java
----------------------------------------------------------------------
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 03344fe..c44c9fa 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
@@ -1,5 +1,3 @@
-// Copyright 2007, 2008, 2010, 2011 The Apache Software Foundation
-//
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
 // You may obtain a copy of the License at
@@ -35,13 +33,13 @@ import org.apache.tapestry5.services.BeanModelSource;
 import org.apache.tapestry5.services.Environment;
 import org.apache.tapestry5.services.FormSupport;
 
-import java.lang.annotation.Annotation;
+import java.util.UUID;
 
 /**
  * A component that generates a user interface for editing the properties of a bean. This
is the central component of
  * the {@link BeanEditForm}, and utilizes a {@link PropertyEditor} for much of its functionality.
This component places
  * a {@link BeanEditContext} into the environment.
- * 
+ *
  * @tapestrydoc
  */
 @SupportsInformalParameters
@@ -183,6 +181,8 @@ public class BeanEditor
         formSupport.storeAndExecute(this, CLEANUP_ENVIRONMENT);
     }
 
+    private String validationId;
+
     /**
      * Used to initialize the model if necessary, to instantiate the object being edited
if necessary, and to push the
      * BeanEditContext into the environment.
@@ -206,8 +206,7 @@ public class BeanEditor
             try
             {
                 object = model.newInstance();
-            }
-            catch (Exception ex)
+            } catch (Exception ex)
             {
                 String message = String.format("Exception instantiating instance of %s (for
component '%s'): %s",
                         PlasticUtils.toTypeName(model.getBeanType()), resources.getCompleteId(),
ex);
@@ -215,13 +214,18 @@ public class BeanEditor
             }
         }
 
+        // Set to a new value on each request; the value lasts until the end of the request.
+        if (validationId == null) {
+            validationId = UUID.randomUUID().toString();
+        }
+
         BeanEditContext context = new BeanEditContextImpl(model.getBeanType());
 
         cachedObject = object;
 
         environment.push(BeanEditContext.class, context);
         // TAP5-2101: Always provide a new BeanValidationContext
-        environment.push(BeanValidationContext.class, new BeanValidationContextImpl(object));
+        environment.push(BeanValidationContext.class, new BeanValidationContextImpl(object,
validationId));
     }
 
     void cleanupEnvironment()
@@ -232,7 +236,7 @@ public class BeanEditor
 
     // For testing
     void inject(ComponentResources resources, PropertyOverrides overrides, BeanModelSource
source,
-            Environment environment)
+                Environment environment)
     {
         this.resources = resources;
         this.overrides = overrides;

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/ef0d1448/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java
b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java
index 78d5615..ea40106 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java
@@ -353,7 +353,7 @@ public class Form implements ClientElement, FormValidationControl
         resources.triggerEvent(EventConstants.PREPARE, context, null);
 
         // Push BeanValidationContext only after the container had a chance to prepare
-        environment.push(BeanValidationContext.class, new BeanValidationContextImpl(validate));
+        environment.push(BeanValidationContext.class, new BeanValidationContextImpl(validate,
null));
 
         // Save the form element for later, in case we want to write an encoding
         // type attribute.
@@ -509,7 +509,7 @@ public class Form implements ClientElement, FormValidationControl
                     return true;
             }
 
-            environment.push(BeanValidationContext.class, new BeanValidationContextImpl(validate));
+            environment.push(BeanValidationContext.class, new BeanValidationContextImpl(validate,
null));
 
             didPushBeanValidationContext = true;
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/ef0d1448/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/PropertyEditBlocks.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/PropertyEditBlocks.java
b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/PropertyEditBlocks.java
index 19326cc..2013319 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/PropertyEditBlocks.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/PropertyEditBlocks.java
@@ -19,6 +19,7 @@ import org.apache.tapestry5.ValueEncoder;
 import org.apache.tapestry5.annotations.Component;
 import org.apache.tapestry5.annotations.Environmental;
 import org.apache.tapestry5.corelib.components.*;
+import org.apache.tapestry5.internal.BeanValidationContext;
 import org.apache.tapestry5.ioc.annotations.Inject;
 import org.apache.tapestry5.ioc.services.TypeCoercer;
 import org.apache.tapestry5.services.BeanBlockContribution;
@@ -39,56 +40,96 @@ public class PropertyEditBlocks
     @Environmental
     private PropertyEditContext context;
 
+    @Environmental
+    private BeanValidationContext validationContext;
+
+    public String getValidationId()
+    {
+        return validationContext.getEditorValidationId() + "-" + context.getPropertyId();
+    }
+
     @Component(
-            parameters = {"value=context.propertyValue", "label=prop:context.label",
-                    "translate=prop:textFieldTranslator", "validate=prop:textFieldValidator",
-                    "clientId=prop:context.propertyId", "annotationProvider=context",
+            parameters = {"value=context.propertyValue",
+                    "label=prop:context.label",
+                    "translate=prop:textFieldTranslator",
+                    "validate=prop:textFieldValidator",
+                    "validationId=validationId",
+                    "clientId=prop:context.propertyId",
+                    "annotationProvider=context",
                     "ensureClientIdUnique=true"})
     private TextField textField;
 
     @Component(
-            parameters = {"value=context.propertyValue", "label=prop:context.label",
-                    "translate=prop:numberFieldTranslator", "validate=prop:numberFieldValidator",
-                    "clientId=prop:context.propertyId", "annotationProvider=context",
+            parameters = {"value=context.propertyValue",
+                    "label=prop:context.label",
+                    "translate=prop:numberFieldTranslator",
+                    "validate=prop:numberFieldValidator",
+                    "validationId=validationId",
+                    "clientId=prop:context.propertyId",
+                    "annotationProvider=context",
                     "ensureClientIdUnique=true"})
     private TextField numberField;
 
 
     @Component(
-            parameters = {"value=context.propertyValue", "label=prop:context.label", "encoder=valueEncoderForProperty",
-                    "model=selectModelForProperty", "validate=prop:selectValidator",
-                    "clientId=prop:context.propertyId", "ensureClientIdUnique=true"})
+            parameters = {"value=context.propertyValue",
+                    "label=prop:context.label",
+                    "encoder=valueEncoderForProperty",
+                    "validationId=validationId",
+                    "model=selectModelForProperty",
+                    "validate=prop:selectValidator",
+                    "clientId=prop:context.propertyId",
+                    "ensureClientIdUnique=true"})
     private Select select;
 
     @SuppressWarnings("unused")
     @Component(
-            parameters = {"value=context.propertyValue", "label=prop:context.label",
-                    "clientId=prop:context.propertyId", "ensureClientIdUnique=true"})
+            parameters = {"value=context.propertyValue",
+                    "label=prop:context.label",
+                    "validationId=validationId",
+                    "clientId=prop:context.propertyId",
+                    "ensureClientIdUnique=true"})
     private Checkbox checkboxField;
 
     @SuppressWarnings("unused")
     @Component(
-            parameters = {"value=context.propertyValue", "label=prop:context.label", "clientId=prop:context.propertyid",
-                    "validate=prop:dateFieldValidator", "ensureClientIdUnique=true"})
+            parameters = {"value=context.propertyValue",
+                    "label=prop:context.label",
+                    "clientId=prop:context.propertyid",
+                    "validate=prop:dateFieldValidator",
+                    "ensureClientIdUnique=true"})
     private DateField dateField;
 
     @SuppressWarnings("unused")
     @Component(
-            parameters = {"value=context.propertyValue", "label=prop:context.label", "clientId=prop:context.propertyid",
-                    "validate=prop:calendarFieldValidator", "ensureClientIdUnique=true"})
+            parameters = {"value=context.propertyValue",
+                    "label=prop:context.label",
+                    "clientId=prop:context.propertyid",
+                    "validate=prop:calendarFieldValidator",
+                    "validationId=validationId",
+                    "ensureClientIdUnique=true"})
     private DateField calendarField;
 
     @Component(
-            parameters = {"value=context.propertyValue", "label=prop:context.label",
-                    "translate=prop:passwordFieldTranslator", "validate=prop:passwordFieldValidator",
-                    "clientId=prop:context.propertyId", "annotationProvider=context", "ensureClientIdUnique=true"})
+            parameters = {"value=context.propertyValue",
+                    "label=prop:context.label",
+                    "translate=prop:passwordFieldTranslator",
+                    "validate=prop:passwordFieldValidator",
+                    "validationId=validationId",
+                    "clientId=prop:context.propertyId",
+                    "annotationProvider=context",
+                    "ensureClientIdUnique=true"})
     private PasswordField passwordField;
 
     @Component(
-            parameters = {"value=context.propertyValue", "label=prop:context.label",
+            parameters = {"value=context.propertyValue",
+                    "label=prop:context.label",
                     "translate=prop:textAreaTranslator",
-                    "validate=prop:textAreaValidator", "clientId=prop:context.propertyId",
-                    "annotationProvider=context", "ensureClientIdUnique=true"})
+                    "validationId=validationId",
+                    "validate=prop:textAreaValidator",
+                    "clientId=prop:context.propertyId",
+                    "annotationProvider=context",
+                    "ensureClientIdUnique=true"})
     private TextArea textArea;
 
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/ef0d1448/tapestry-core/src/main/java/org/apache/tapestry5/internal/BeanValidationContext.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/BeanValidationContext.java
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/BeanValidationContext.java
index 29c0f85..707101d 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/BeanValidationContext.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/BeanValidationContext.java
@@ -1,5 +1,3 @@
-// Copyright 2009, 2010 The Apache Software Foundation
-//
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
 // You may obtain a copy of the License at
@@ -15,7 +13,7 @@ package org.apache.tapestry5.internal;
 
 /**
  * Defines a context for validating beans.
- * 
+ *
  * @since 5.2.0
  */
 public interface BeanValidationContext
@@ -24,21 +22,29 @@ public interface BeanValidationContext
      * Returns the type of the object to validate. This method is needed for client side
validation.
      */
     Class getBeanType();
-    
+
     /**
      * Return the object to validate.
      */
     Object getBeanInstance();
-    
+
     /**
      * Returns name of the property to validate. The current name is overwritten by every
form field.
      */
     String getCurrentProperty();
-    
+
     /**
      * Sets name of the property to validate.
-     * 
-     * @param propertyName name of the property
+     *
+     * @param propertyName
+     *         name of the property
      */
     void setCurrentProperty(String propertyName);
+
+    /**
+     * Returns a validation id that should be used as a prefix for any fields inside a {@link
org.apache.tapestry5.corelib.components.BeanEditor}.
+     *
+     * @since 5.4
+     */
+    String getEditorValidationId();
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/ef0d1448/tapestry-core/src/main/java/org/apache/tapestry5/internal/BeanValidationContextImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/BeanValidationContextImpl.java
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/BeanValidationContextImpl.java
index c52d897..2f3d83c 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/BeanValidationContextImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/BeanValidationContextImpl.java
@@ -1,5 +1,3 @@
-// Copyright 2010 The Apache Software Foundation
-//
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
 // You may obtain a copy of the License at
@@ -16,17 +14,21 @@ package org.apache.tapestry5.internal;
 
 public class BeanValidationContextImpl implements BeanValidationContext
 {
-    private Object bean;
+    private final Object bean;
+
+    private final String editorValidationId;
+
     private String currentProperty;
 
-    public BeanValidationContextImpl(Object bean)
+    public BeanValidationContextImpl(Object bean, String editorValidationId)
     {
         this.bean = bean;
+        this.editorValidationId = editorValidationId;
     }
 
     public Class getBeanType()
     {
-        return bean==null?null:bean.getClass();
+        return bean == null ? null : bean.getClass();
     }
 
     public Object getBeanInstance()
@@ -34,14 +36,18 @@ public class BeanValidationContextImpl implements BeanValidationContext
         return bean;
     }
 
-    public String getCurrentProperty() 
+    public String getCurrentProperty()
     {
         return currentProperty;
     }
 
-    public void setCurrentProperty(String propertyName) 
+    public void setCurrentProperty(String propertyName)
     {
         this.currentProperty = propertyName;
     }
 
+    public String getEditorValidationId()
+    {
+        return editorValidationId;
+    }
 }


Mime
View raw message