You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@bval.apache.org by ro...@apache.org on 2010/05/04 17:35:16 UTC

svn commit: r940911 - in /incubator/bval/trunk/bval-jsr303/src: main/java/org/apache/bval/jsr303/ main/java/org/apache/bval/jsr303/extensions/ test/java/org/apache/bval/jsr303/ test/java/org/apache/bval/jsr303/xml/

Author: romanstumm
Date: Tue May  4 15:35:16 2010
New Revision: 940911

URL: http://svn.apache.org/viewvc?rev=940911&view=rev
Log:
BVAL-35  Improved support of @OverridesAttribute - from Carlos Varla

Added:
    incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/BaseAppendValidation.java
Modified:
    incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/AnnotationConstraintBuilder.java
    incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/AppendValidationToBuilder.java
    incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/AppendValidationToMeta.java
    incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/ConstraintValidation.java
    incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/Jsr303MetaBeanFactory.java
    incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/extensions/AppendValidationToList.java
    incubator/bval/trunk/bval-jsr303/src/test/java/org/apache/bval/jsr303/ComposedConstraintsTest.java
    incubator/bval/trunk/bval-jsr303/src/test/java/org/apache/bval/jsr303/ConstraintCompositionTest.java
    incubator/bval/trunk/bval-jsr303/src/test/java/org/apache/bval/jsr303/xml/ValidationParserTest.java

Modified: incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/AnnotationConstraintBuilder.java
URL: http://svn.apache.org/viewvc/incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/AnnotationConstraintBuilder.java?rev=940911&r1=940910&r2=940911&view=diff
==============================================================================
--- incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/AnnotationConstraintBuilder.java (original)
+++ incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/AnnotationConstraintBuilder.java Tue May  4 15:35:16 2010
@@ -21,6 +21,7 @@ package org.apache.bval.jsr303;
 
 import org.apache.bval.jsr303.groups.GroupsComputer;
 import org.apache.bval.jsr303.util.SecureActions;
+import org.apache.bval.jsr303.xml.AnnotationProxyBuilder;
 import org.apache.bval.util.AccessStrategy;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -156,30 +157,44 @@ final class AnnotationConstraintBuilder 
         constraintValidation.addComposed(composite); // add AFTER apply()
     }
 
-    private void applyOverridesAttributes(ConstraintValidation composite) {
-        if (null == overrides) buildOverridesAttributes();
+    private void applyOverridesAttributes(ConstraintValidation<?> composite) {
+        if (null == overrides) {
+            buildOverridesAttributes();
+        }
         if (!overrides.isEmpty()) {
-            int index = computeIndex(composite); // assume composite not yet added! (+1)
-            if (index < 0) {
-                ConstraintOverrides override = // search for constraintIndex = -1
-                      findOverride(composite.getAnnotation().annotationType(), -1);
-                if (override != null) override.applyOn(composite);
-                else override = // search for constraintIndex == 0
-                      findOverride(composite.getAnnotation().annotationType(), 0);
-                if (override != null) override.applyOn(composite);
-            } else { // search for constraintIndex > 0
-                ConstraintOverrides override =
-                      findOverride(composite.getAnnotation().annotationType(), index + 1);
-                if (override != null) override.applyOn(composite);
+            int index = computeIndex(composite);
+
+            // Search for the overrides to apply
+            ConstraintOverrides generalOverride = findOverride(composite.getAnnotation().annotationType(), -1);
+            if ( generalOverride != null ) {
+                if ( index > 0 ) {
+                    throw new ConstraintDeclarationException("Wrong OverridesAttribute declaration for " + generalOverride.constraintType + ", it needs a defined index when there is a list of constraints");
+                }
+                generalOverride.applyOn(composite);
+            }
+
+            ConstraintOverrides override = findOverride(composite.getAnnotation().annotationType(), index);
+            if ( override != null ) {
+                override.applyOn(composite);
             }
+            
         }
     }
 
-    private int computeIndex(ConstraintValidation composite) {
-        int idx = -1;
+    
+    /**
+     * Calculates the index of the composite constraint. The index represents
+     * the order in which it is added in reference to other constraints of the
+     * same type.
+     * 
+     * @param composite
+     *            The composite constraint (not yet added).
+     * @return An integer index always >= 0
+     */
+    private int computeIndex(ConstraintValidation<?> composite) {
+        int idx = 0;
         for (ConstraintValidation<?> each : constraintValidation.getComposingValidations()) {
-            if (each.getAnnotation().annotationType() ==
-                  composite.getAnnotation().annotationType()) {
+            if (each.getAnnotation().annotationType() == composite.getAnnotation().annotationType()) {
                 idx++;
             }
         }
@@ -188,7 +203,7 @@ final class AnnotationConstraintBuilder 
 
     /** read overridesAttributes from constraintValidation.annotation */
     private void buildOverridesAttributes() {
-        overrides = new LinkedList();
+        overrides = new LinkedList<ConstraintOverrides>();
         for (Method method : constraintValidation.getAnnotation()
               .annotationType()
               .getDeclaredMethods()) {
@@ -246,7 +261,17 @@ final class AnnotationConstraintBuilder 
         }
 
         public void applyOn(ConstraintValidation composite) {
+            // Update the attributes
             composite.getAttributes().putAll(values);
+            
+            // And the annotation
+            Annotation originalAnnot = composite.getAnnotation();
+            AnnotationProxyBuilder<Annotation> apb = new AnnotationProxyBuilder<Annotation>(originalAnnot);
+            for ( String key : values.keySet() ) {
+                apb.putValue(key, values.get(key));
+            }
+            Annotation newAnnot = apb.createAnnotation();
+            composite.setAnnotation(newAnnot);
         }
     }
 }

Modified: incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/AppendValidationToBuilder.java
URL: http://svn.apache.org/viewvc/incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/AppendValidationToBuilder.java?rev=940911&r1=940910&r2=940911&view=diff
==============================================================================
--- incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/AppendValidationToBuilder.java (original)
+++ incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/AppendValidationToBuilder.java Tue May  4 15:35:16 2010
@@ -25,14 +25,14 @@ import java.util.Set;
 /**
  * Description: <br/>
  */
-public class AppendValidationToBuilder implements AppendValidation {
+public class AppendValidationToBuilder extends BaseAppendValidation {
     private final AnnotationConstraintBuilder builder;
 
     public AppendValidationToBuilder(AnnotationConstraintBuilder builder) {
         this.builder = builder;
     }
 
-    public <T extends Annotation> void append(ConstraintValidation<T> validation) {
+    public <T extends Annotation> void preProcessValidation(ConstraintValidation<T> validation) {
         // JSR-303 2.3:
         // Groups from the main constraint annotation are inherited by the composing annotations.
         // Any groups definition on a composing annotation is ignored.
@@ -52,8 +52,9 @@ public class AppendValidationToBuilder i
         apb.putValue("payload", inheritedPayload.toArray(new Class[inheritedPayload.size()]));
         T newAnnot = apb.createAnnotation();
         validation.setAnnotation(newAnnot);
-        
-        // And finally, add the composed validation
+    }
+    
+    public <T extends Annotation> void performAppend(ConstraintValidation<T> validation) {
         builder.addComposed(validation);
     }
     

Modified: incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/AppendValidationToMeta.java
URL: http://svn.apache.org/viewvc/incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/AppendValidationToMeta.java?rev=940911&r1=940910&r2=940911&view=diff
==============================================================================
--- incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/AppendValidationToMeta.java (original)
+++ incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/AppendValidationToMeta.java Tue May  4 15:35:16 2010
@@ -16,21 +16,21 @@
  */
 package org.apache.bval.jsr303;
 
-import java.lang.annotation.Annotation;
-
 import org.apache.bval.model.FeaturesCapable;
 
+import java.lang.annotation.Annotation;
+
 /**
  * Description: <br/>
  */
-public class AppendValidationToMeta implements AppendValidation {
+public class AppendValidationToMeta extends BaseAppendValidation {
     private final FeaturesCapable feature;
 
     public AppendValidationToMeta(FeaturesCapable meta) {
         this.feature = meta;
     }
 
-    public <T extends Annotation> void append(ConstraintValidation<T> validation) {
+    public <T extends Annotation> void performAppend(ConstraintValidation<T> validation) {
         feature.addValidation(validation);
     }
 }

Added: incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/BaseAppendValidation.java
URL: http://svn.apache.org/viewvc/incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/BaseAppendValidation.java?rev=940911&view=auto
==============================================================================
--- incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/BaseAppendValidation.java (added)
+++ incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/BaseAppendValidation.java Tue May  4 15:35:16 2010
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+package org.apache.bval.jsr303;
+
+import java.lang.annotation.Annotation;
+
+/**
+ * Abstract base validation appender that initializes the
+ * {@link ConstraintValidation#getValidator()} on post-processing.
+ * 
+ * @author Carlos Vara
+ */
+public abstract class BaseAppendValidation implements AppendValidation {
+
+    /**
+     * Append operation divided in 3 stages: pre & post processing and the
+     * "real" append process.
+     */
+    public final <T extends Annotation> void append(ConstraintValidation<T> validation) {
+        preProcessValidation(validation);
+        performAppend(validation);
+        postProcessValidation(validation);
+    }
+
+    /**
+     * Performs the actual "appending" operation to the underlying data
+     * structure that holds the validations. Implementations shouldn't try to do
+     * more than that in this step.
+     * 
+     * @param <T>
+     *            The type of the validation.
+     * @param validation
+     *            The validation to be appended.
+     */
+    public abstract <T extends Annotation> void performAppend(ConstraintValidation<T> validation);
+
+    /**
+     * Pre-process the validation before appending it.
+     * 
+     * @param <T>
+     *            The type of the validation.
+     * @param validation
+     *            The validation to be appended.
+     */
+    public <T extends Annotation> void preProcessValidation(ConstraintValidation<T> validation) {
+        // No generic pre-processing
+    }
+    
+    /**
+     * Post-process the validation once it has been appended.
+     * 
+     * @param <T>
+     *            The type of the validation.
+     * @param validation
+     *            The validation to be appended.
+     */
+    public <T extends Annotation> void postProcessValidation(ConstraintValidation<T> validation) {
+        // Initialize the validator
+        validation.initialize();
+    }
+    
+}

Modified: incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/ConstraintValidation.java
URL: http://svn.apache.org/viewvc/incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/ConstraintValidation.java?rev=940911&r1=940910&r2=940911&view=diff
==============================================================================
--- incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/ConstraintValidation.java (original)
+++ incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/ConstraintValidation.java Tue May  4 15:35:16 2010
@@ -27,6 +27,7 @@ import org.apache.bval.model.ValidationC
 import org.apache.bval.model.ValidationListener;
 import org.apache.bval.util.AccessStrategy;
 
+import javax.validation.ConstraintDefinitionException;
 import javax.validation.ConstraintValidator;
 import javax.validation.Payload;
 import javax.validation.ValidationException;
@@ -150,6 +151,9 @@ public class ConstraintValidation<T exte
             }
         }
 
+        // Restore current constraint validation
+        context.setConstraintValidation(this);
+        
         if (validator != null) {
             ConstraintValidatorContextImpl jsrContext =
                   new ConstraintValidatorContextImpl(context, this);
@@ -159,6 +163,23 @@ public class ConstraintValidation<T exte
         }
     }
 
+    /**
+     * Initialize the validator (if not <code>null</code>) with the stored
+     * annotation.
+     */
+    public void initialize() {
+        if (null != validator) {
+            try {
+                validator.initialize(annotation);
+            } catch (RuntimeException e) {
+                // Either a "legit" problem initializing the validator or a
+                // ClassCastException if the validator associated annotation is 
+                // not a supertype of the validated annotation.
+                throw new ConstraintDefinitionException("Incorrect validator [" + validator.getClass().getCanonicalName() + "] for annotation " + annotation.annotationType().getCanonicalName(), e);
+            }
+        }
+    }
+
     private boolean isCascadeEnabled(GroupValidationContext context) {
         PathImpl path = context.getPropertyPath();
         NodeImpl node = path.getLeafNode();

Modified: incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/Jsr303MetaBeanFactory.java
URL: http://svn.apache.org/viewvc/incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/Jsr303MetaBeanFactory.java?rev=940911&r1=940910&r2=940911&view=diff
==============================================================================
--- incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/Jsr303MetaBeanFactory.java (original)
+++ incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/Jsr303MetaBeanFactory.java Tue May  4 15:35:16 2010
@@ -437,13 +437,7 @@ public class Jsr303MetaBeanFactory imple
             checkOneType(assignableTypes, type, owner, annotation, access);
             validator = getConstraintValidatorFactory()
                   .getInstance(validatorTypes.get(assignableTypes.get(0)));
-            try {
-                validator.initialize(annotation);
-            } catch (RuntimeException e) {
-                // Either a "legit" problem initializing the validator or a ClassCastException if
-                // the validator associated annotation is not a supertype of the validated annotation.
-                throw new ConstraintDefinitionException("Incorrect validator ["+validator.getClass().getCanonicalName()+"] for annotation " + annotation.annotationType().getCanonicalName(), e);
-            }
+            // NOTE: validator initialization deferred until append phase
         } else {
             validator = null;
         }

Modified: incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/extensions/AppendValidationToList.java
URL: http://svn.apache.org/viewvc/incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/extensions/AppendValidationToList.java?rev=940911&r1=940910&r2=940911&view=diff
==============================================================================
--- incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/extensions/AppendValidationToList.java (original)
+++ incubator/bval/trunk/bval-jsr303/src/main/java/org/apache/bval/jsr303/extensions/AppendValidationToList.java Tue May  4 15:35:16 2010
@@ -17,23 +17,23 @@
 package org.apache.bval.jsr303.extensions;
 
 
+import org.apache.bval.jsr303.BaseAppendValidation;
+import org.apache.bval.jsr303.ConstraintValidation;
+
 import java.lang.annotation.Annotation;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.apache.bval.jsr303.AppendValidation;
-import org.apache.bval.jsr303.ConstraintValidation;
-
 /**
  * Description: <br/>
  */
-public class AppendValidationToList implements AppendValidation {
+public class AppendValidationToList extends BaseAppendValidation {
     private final List<ConstraintValidation<? extends Annotation>> validations = new ArrayList<ConstraintValidation<? extends Annotation>>();
 
     public AppendValidationToList() {
     }
 
-    public <T extends Annotation> void append(ConstraintValidation<T> validation) {
+    public <T extends Annotation> void performAppend(ConstraintValidation<T> validation) {
         validations.add(validation);
     }
 

Modified: incubator/bval/trunk/bval-jsr303/src/test/java/org/apache/bval/jsr303/ComposedConstraintsTest.java
URL: http://svn.apache.org/viewvc/incubator/bval/trunk/bval-jsr303/src/test/java/org/apache/bval/jsr303/ComposedConstraintsTest.java?rev=940911&r1=940910&r2=940911&view=diff
==============================================================================
--- incubator/bval/trunk/bval-jsr303/src/test/java/org/apache/bval/jsr303/ComposedConstraintsTest.java (original)
+++ incubator/bval/trunk/bval-jsr303/src/test/java/org/apache/bval/jsr303/ComposedConstraintsTest.java Tue May  4 15:35:16 2010
@@ -79,7 +79,7 @@ public class ComposedConstraintsTest ext
         ConstraintViolation<FrenchAddress> finding = findings.iterator().next();
         Assert.assertEquals("Wrong zipcode", finding.getMessage());
 
-        adr.setZipCode("12345");
+        adr.setZipCode("1234567");
         findings = val.validate(adr);
         Assert.assertEquals(0, findings.size());
 

Modified: incubator/bval/trunk/bval-jsr303/src/test/java/org/apache/bval/jsr303/ConstraintCompositionTest.java
URL: http://svn.apache.org/viewvc/incubator/bval/trunk/bval-jsr303/src/test/java/org/apache/bval/jsr303/ConstraintCompositionTest.java?rev=940911&r1=940910&r2=940911&view=diff
==============================================================================
--- incubator/bval/trunk/bval-jsr303/src/test/java/org/apache/bval/jsr303/ConstraintCompositionTest.java (original)
+++ incubator/bval/trunk/bval-jsr303/src/test/java/org/apache/bval/jsr303/ConstraintCompositionTest.java Tue May  4 15:35:16 2010
@@ -24,6 +24,7 @@ import junit.framework.TestCase;
 
 import javax.validation.*;
 import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
 import javax.validation.metadata.ConstraintDescriptor;
 import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
@@ -134,11 +135,43 @@ public class ConstraintCompositionTest e
         Assert.assertEquals("There should only be 1 payload class", 1, notNullPayload.size());
         Assert.assertTrue("Payload1 should be the only payload", notNullPayload.contains(Payload1.class));
     }
-    
+
+    /**
+     * Checks that {@link OverridesAttribute#constraintIndex()} parsing and
+     * applying works.
+     */
+    public void testIndexedOverridesAttributes() {
+        Validator validator = getValidator();
+        
+        Person p = new Person();
+        p.name = "valid";
+        
+        // With a valid id, no errors expected
+        p.id = "1234";
+        Set<ConstraintViolation<Person>> constraintViolations = validator.validate(p);
+        Assert.assertTrue("No violations should be reported on valid id", constraintViolations.isEmpty());
+        
+        // With a short id, only 1 error expected
+        p.id = "1";
+        constraintViolations = validator.validate(p);
+        Assert.assertEquals("Only 1 violation expected", 1, constraintViolations.size());
+        ConstraintViolation<Person> violation = constraintViolations.iterator().next();
+        Assert.assertEquals("Wrong violation", "Id is too short", violation.getMessage());
+        
+        // With a long id, only 1 error expected
+        p.id = "loooooong id";
+        constraintViolations = validator.validate(p);
+        Assert.assertEquals("Only 1 violation expected", 1, constraintViolations.size());
+        violation = constraintViolations.iterator().next();
+        Assert.assertEquals("Wrong violation", "Id is too long", violation.getMessage());
+    }
     
     public static class Person {
         @PersonName
         String name;
+        
+        @PersonId
+        String id;
     }
     
     public static class Man {
@@ -168,6 +201,25 @@ public class ConstraintCompositionTest e
         Class<? extends Payload>[] payload() default {};
     }
     
+    
+    @Size.List({ @Size(min=3, max=3, message="Id is too short"), @Size(min=5,max=5, message="Id is too long") })
+    @Constraint(validatedBy = {})
+    @Documented
+    @Target({ METHOD, FIELD, TYPE })
+    @Retention(RUNTIME)
+    public static @interface PersonId {
+        String message() default "Wrong person id";
+        Class<?>[] groups() default { };
+        Class<? extends Payload>[] payload() default {};
+        
+        @OverridesAttribute(constraint=Size.class,constraintIndex=0,name="max")
+        int maxSize() default 1000;
+        
+        @OverridesAttribute(constraint=Size.class,constraintIndex=1,name="min")
+        int minSize() default 0;
+        
+    }
+    
     public static interface Group1 {
     }
     

Modified: incubator/bval/trunk/bval-jsr303/src/test/java/org/apache/bval/jsr303/xml/ValidationParserTest.java
URL: http://svn.apache.org/viewvc/incubator/bval/trunk/bval-jsr303/src/test/java/org/apache/bval/jsr303/xml/ValidationParserTest.java?rev=940911&r1=940910&r2=940911&view=diff
==============================================================================
--- incubator/bval/trunk/bval-jsr303/src/test/java/org/apache/bval/jsr303/xml/ValidationParserTest.java (original)
+++ incubator/bval/trunk/bval-jsr303/src/test/java/org/apache/bval/jsr303/xml/ValidationParserTest.java Tue May  4 15:35:16 2010
@@ -21,19 +21,16 @@ package org.apache.bval.jsr303.xml;
 import junit.framework.Test;
 import junit.framework.TestCase;
 import junit.framework.TestSuite;
-
-import javax.validation.ConstraintViolation;
-import javax.validation.Validation;
-import javax.validation.Validator;
-import javax.validation.ValidatorFactory;
-
 import org.apache.bval.jsr303.ApacheValidationProvider;
 import org.apache.bval.jsr303.ApacheValidatorConfiguration;
 import org.apache.bval.jsr303.ConfigurationImpl;
 import org.apache.bval.jsr303.example.XmlEntitySampleBean;
 import org.apache.bval.jsr303.resolver.SimpleTraversableResolver;
-import org.apache.bval.jsr303.xml.ValidationParser;
 
+import javax.validation.ConstraintViolation;
+import javax.validation.Validation;
+import javax.validation.Validator;
+import javax.validation.ValidatorFactory;
 import java.util.Set;
 
 /**
@@ -82,7 +79,7 @@ public class ValidationParserTest extend
         assertTrue(!results.isEmpty());
         assertTrue(results.size() == 3);
 
-        bean.setZipCode("valid");
+        bean.setZipCode("123");
         bean.setValueCode("20");
         bean.setFirstName("valid");
         results = validator.validate(bean);