bval-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mben...@apache.org
Subject svn commit: r993590 - in /incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303: AnnotationProcessor.java Jsr303MetaBeanFactory.java extensions/MethodValidatorMetaBeanFactory.java util/TypeUtils.java
Date Wed, 08 Sep 2010 02:42:15 GMT
Author: mbenson
Date: Wed Sep  8 02:42:15 2010
New Revision: 993590

URL: http://svn.apache.org/viewvc?rev=993590&view=rev
Log:
extract AnnotationProcessor from Jsr303MetaBeanFactory; remove bval TypeUtils, moving a couple
of things into AnnotationProcessor and replacing the rest with lang3 TypeUtils

Added:
    incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/AnnotationProcessor.java
  (with props)
Removed:
    incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/util/TypeUtils.java
Modified:
    incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/Jsr303MetaBeanFactory.java
    incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/extensions/MethodValidatorMetaBeanFactory.java

Added: incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/AnnotationProcessor.java
URL: http://svn.apache.org/viewvc/incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/AnnotationProcessor.java?rev=993590&view=auto
==============================================================================
--- incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/AnnotationProcessor.java
(added)
+++ incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/AnnotationProcessor.java
Wed Sep  8 02:42:15 2010
@@ -0,0 +1,430 @@
+/*
+ * 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;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Array;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.validation.Constraint;
+import javax.validation.ConstraintValidator;
+import javax.validation.UnexpectedTypeException;
+import javax.validation.Valid;
+import javax.validation.ValidationException;
+import javax.validation.groups.Default;
+
+import org.apache.bval.jsr303.util.ConstraintDefinitionValidator;
+import org.apache.bval.jsr303.util.SecureActions;
+import org.apache.bval.model.Features;
+import org.apache.bval.model.MetaBean;
+import org.apache.bval.model.MetaProperty;
+import org.apache.bval.util.AccessStrategy;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.ClassUtils;
+import org.apache.commons.lang3.reflect.TypeUtils;
+
+/**
+ * Description: implements uniform handling of JSR303 {@link Constraint}
+ * annotations, including composed constraints and the resolution of
+ * {@link ConstraintValidator} implementations.
+ * 
+ * @version $Rev$ $Date$
+ */
+public final class AnnotationProcessor {
+    /** {@link ApacheFactoryContext} used */
+    private final ApacheFactoryContext factoryContext;
+
+    /**
+     * Create a new {@link AnnotationProcessor} instance.
+     * 
+     * @param factoryContext
+     */
+    public AnnotationProcessor(ApacheFactoryContext factoryContext) {
+        this.factoryContext = factoryContext;
+    }
+
+    /**
+     * Process JSR303 annotations.
+     * 
+     * @param prop
+     *            potentially null
+     * @param owner
+     *            bean type
+     * @param element
+     *            whose annotations to read
+     * @param access
+     *            strategy for <code>prop</code>
+     * @param appender
+     *            handling accumulation
+     * @return whether any processing took place
+     * @throws IllegalAccessException
+     * @throws InvocationTargetException
+     */
+    public boolean processAnnotations(MetaProperty prop, Class<?> owner, AnnotatedElement
element,
+        AccessStrategy access, AppendValidation appender) throws IllegalAccessException,
InvocationTargetException {
+
+        boolean changed = false;
+        for (Annotation annotation : element.getDeclaredAnnotations()) {
+            changed |= processAnnotation(annotation, prop, owner, access, appender);
+        }
+        return changed;
+    }
+
+    /**
+     * Process a single annotation.
+     * 
+     * @param <A>
+     *            annotation type
+     * @param annotation
+     *            to process
+     * @param prop
+     *            potentially null
+     * @param owner
+     *            bean type
+     * @param access
+     *            strategy for <code>prop</code>
+     * @param appender
+     *            handling accumulation
+     * @return whether any processing took place
+     * @throws IllegalAccessException
+     * @throws InvocationTargetException
+     */
+    public <A extends Annotation> boolean processAnnotation(A annotation, MetaProperty
prop, Class<?> owner,
+        AccessStrategy access, AppendValidation appender) throws IllegalAccessException,
InvocationTargetException {
+        if (annotation instanceof Valid) {
+            return addAccessStrategy(prop, access);
+        }
+        /**
+         * An annotation is considered a constraint definition if its retention
+         * policy contains RUNTIME and if the annotation itself is annotated
+         * with javax.validation.Constraint.
+         */
+        Constraint vcAnno = annotation.annotationType().getAnnotation(Constraint.class);
+        if (vcAnno != null) {
+            ConstraintDefinitionValidator.validateConstraintDefinition(annotation);
+            Class<? extends ConstraintValidator<A, ?>>[] validatorClasses;
+            validatorClasses = findConstraintValidatorClasses(annotation, vcAnno);
+            return applyConstraint(annotation, validatorClasses, prop, owner, access, appender);
+        }
+        /**
+         * Multi-valued constraints: To support this requirement, the bean
+         * validation provider treats regular annotations (annotations not
+         * annotated by @Constraint) whose value element has a return type of an
+         * array of constraint annotations in a special way.
+         */
+        Object result =
+            SecureActions.getAnnotationValue(annotation, "value");
+        if (result != null && result instanceof Annotation[]) {
+            boolean changed = false;
+            for (Annotation each : (Annotation[]) result) {
+                changed |= processAnnotation(each, prop, owner, access, appender);
+            }
+            return changed;
+        }
+        return false;
+    }
+
+    /**
+     * Add the specified {@link AccessStrategy} to <code>prop</code>; noop if
+     * <code>prop == null</code>.
+     * 
+     * @param prop
+     * @param access
+     * @return whether anything took place.
+     */
+    public boolean addAccessStrategy(MetaProperty prop, AccessStrategy access) {
+        if (prop == null) {
+            return false;
+        }
+        AccessStrategy[] strategies = prop.getFeature(Features.Property.REF_CASCADE);
+        if (strategies == null) {
+            strategies = new AccessStrategy[] { access };
+            prop.putFeature(Features.Property.REF_CASCADE, strategies);
+        } else if (!ArrayUtils.contains(strategies, access)) {
+            prop.putFeature(Features.Property.REF_CASCADE, ArrayUtils.add(strategies, access));
+        }
+        return true;
+    }
+
+    /**
+     * Find available {@link ConstraintValidation} classes for a given
+     * constraint annotation.
+     * 
+     * @param annotation
+     * @param vcAnno
+     * @return {@link ConstraintValidation} implementation class array
+     */
+    @SuppressWarnings("unchecked")
+    private <A extends Annotation> Class<? extends ConstraintValidator<A, ?>>[]
findConstraintValidatorClasses(
+        A annotation, Constraint vcAnno) {
+        if (vcAnno == null) {
+            vcAnno = annotation.annotationType().getAnnotation(Constraint.class);
+        }
+        Class<? extends ConstraintValidator<A, ?>>[] validatorClasses;
+        Class<A> annotationType = (Class<A>) annotation.annotationType();
+        validatorClasses = factoryContext.getFactory().getConstraintsCache().getConstraintValidators(annotationType);
+        if (validatorClasses == null) {
+            validatorClasses = (Class<? extends ConstraintValidator<A, ?>>[])
vcAnno.validatedBy();
+            if (validatorClasses.length == 0) {
+                validatorClasses =
+                    factoryContext.getFactory().getDefaultConstraints().getValidatorClasses(annotationType);
+            }
+        }
+        return validatorClasses;
+    }
+
+    /**
+     * Apply a constraint to the specified <code>appender</code>.
+     * 
+     * @param annotation
+     *            constraint annotation
+     * @param constraintClasses
+     *            known {@link ConstraintValidator} implementation classes for
+     *            <code>annotation</code>
+     * @param prop
+     *            meta-property
+     * @param owner
+     *            type
+     * @param access
+     *            strategy
+     * @param appender
+     * @return success flag
+     * @throws IllegalAccessException
+     * @throws InvocationTargetException
+     */
+    private <A extends Annotation> boolean applyConstraint(A annotation,
+        Class<? extends ConstraintValidator<A, ?>>[] constraintClasses, MetaProperty
prop, Class<?> owner,
+        AccessStrategy access, AppendValidation appender) throws IllegalAccessException,
InvocationTargetException {
+
+        final ConstraintValidator<A, ?> validator =
+            getConstraintValidator(annotation, constraintClasses, owner, access);
+        final AnnotationConstraintBuilder<A> builder =
+            new AnnotationConstraintBuilder<A>(constraintClasses, validator, annotation,
owner, access);
+
+        // JSR-303 3.4.4: Add implicit groups
+        if (prop != null && prop.getParentMetaBean() != null) {
+            MetaBean parentMetaBean = prop.getParentMetaBean();
+            // If:
+            // - the owner is an interface
+            // - the class of the metabean being build is different than the
+            // owner
+            // - and only the Default group is defined
+            // Then: add the owner interface as implicit groups
+            if (builder.getConstraintValidation().getOwner().isInterface()
+                && parentMetaBean.getBeanClass() != builder.getConstraintValidation().getOwner()
+                && builder.getConstraintValidation().getGroups().size() == 1
+                && builder.getConstraintValidation().getGroups().contains(Default.class))
{
+                Set<Class<?>> groups = builder.getConstraintValidation().getGroups();
+                groups.add(builder.getConstraintValidation().getOwner());
+                builder.getConstraintValidation().setGroups(groups);
+            }
+        }
+
+        // If already building a constraint composition tree, ensure that:
+        // - the parent groups are inherited
+        // - the parent payload is inherited
+        if (appender instanceof AppendValidationToBuilder) {
+            AppendValidationToBuilder avb = (AppendValidationToBuilder) appender;
+            builder.getConstraintValidation().setGroups(avb.getInheritedGroups());
+            builder.getConstraintValidation().setPayload(avb.getInheritedPayload());
+        }
+
+        // process composed constraints:
+        // here are not other superclasses possible, because annotations do not
+        // inherit!
+        processAnnotations(prop, owner, annotation.annotationType(), access, new AppendValidationToBuilder(builder));
+
+        // Even if the validator is null, it must be added to mimic the RI impl
+        appender.append(builder.getConstraintValidation());
+        return true;
+    }
+
+    private <A extends Annotation, T> ConstraintValidator<A, ? super T> getConstraintValidator(A
annotation,
+        Class<? extends ConstraintValidator<A, ?>>[] constraintClasses, Class<?>
owner, AccessStrategy access) {
+        if (constraintClasses != null && constraintClasses.length > 0) {
+            Type type = determineTargetedType(owner, access);
+            /**
+             * spec says in chapter 3.5.3.: The ConstraintValidator chosen to
+             * validate a declared type T is the one where the type supported by
+             * the ConstraintValidator is a supertype of T and where there is no
+             * other ConstraintValidator whose supported type is a supertype of
+             * T and not a supertype of the chosen ConstraintValidator supported
+             * type.
+             */
+            Map<Type, Class<? extends ConstraintValidator<A, ?>>> validatorTypes
=
+                getValidatorsTypes(constraintClasses);
+            final List<Type> assignableTypes = new ArrayList<Type>(constraintClasses.length);
+            fillAssignableTypes(type, validatorTypes.keySet(), assignableTypes);
+            reduceAssignableTypes(assignableTypes);
+            checkOneType(assignableTypes, type, owner, annotation, access);
+
+            @SuppressWarnings("unchecked")
+            final ConstraintValidator<A, ? super T> validator =
+                (ConstraintValidator<A, ? super T>) factoryContext.getFactory().getConstraintValidatorFactory()
+                    .getInstance(validatorTypes.get(assignableTypes.get(0)));
+            if (validator == null) {
+                throw new ValidationException("Factory returned null validator for: "
+                    + validatorTypes.get(assignableTypes.get(0)));
+
+            }
+            return validator;
+            // NOTE: validator initialization deferred until append phase
+        }
+        return null;
+    }
+
+    private static void checkOneType(List<Type> types, Type targetType, Class<?>
owner, Annotation anno,
+        AccessStrategy access) {
+
+        if (types.isEmpty()) {
+            StringBuilder buf =
+                new StringBuilder().append("No validator could be found for type ").append(stringForType(targetType))
+                    .append(". See: @").append(anno.annotationType().getSimpleName()).append("
at ").append(
+                        stringForLocation(owner, access));
+            throw new UnexpectedTypeException(buf.toString());
+        } else if (types.size() > 1) {
+            StringBuilder buf = new StringBuilder();
+            buf.append("Ambiguous validators for type ");
+            buf.append(stringForType(targetType));
+            buf.append(". See: @").append(anno.annotationType().getSimpleName()).append("
at ").append(
+                stringForLocation(owner, access));
+            buf.append(". Validators are: ");
+            boolean comma = false;
+            for (Type each : types) {
+                if (comma)
+                    buf.append(", ");
+                comma = true;
+                buf.append(each);
+            }
+            throw new UnexpectedTypeException(buf.toString());
+        }
+    }
+
+    /** implements spec chapter 3.5.3. ConstraintValidator resolution algorithm. */
+    private static Type determineTargetedType(Class<?> owner, AccessStrategy access)
{
+        // if the constraint declaration is hosted on a class or an interface,
+        // the targeted type is the class or the interface.
+        if (access == null)
+            return owner;
+        Type type = access.getJavaType();
+        if (type == null)
+            return Object.class;
+        if (type instanceof Class<?>)
+            type = ClassUtils.primitiveToWrapper((Class<?>) type);
+        return type;
+    }
+
+    private static String stringForType(Type clazz) {
+        if (clazz instanceof Class<?>) {
+            if (((Class<?>) clazz).isArray()) {
+                return ((Class<?>) clazz).getComponentType().getName() + "[]";
+            } else {
+                return ((Class<?>) clazz).getName();
+            }
+        } else {
+            return clazz.toString();
+        }
+    }
+
+    private static String stringForLocation(Class<?> owner, AccessStrategy access)
{
+        if (access != null) {
+            return access.toString();
+        } else {
+            return owner.getName();
+        }
+    }
+
+    private static void fillAssignableTypes(Type type, Set<Type> validatorsTypes, List<Type>
suitableTypes) {
+        for (Type validatorType : validatorsTypes) {
+            if (org.apache.commons.lang3.reflect.TypeUtils.isAssignable(type, validatorType)
+                && !suitableTypes.contains(validatorType)) {
+                suitableTypes.add(validatorType);
+            }
+        }
+    }
+
+    /**
+     * Tries to reduce all assignable classes down to a single class.
+     * 
+     * @param assignableTypes
+     *            The set of all classes which are assignable to the class of
+     *            the value to be validated and which are handled by at least
+     *            one of the validators for the specified constraint.
+     */
+    private static void reduceAssignableTypes(List<Type> assignableTypes) {
+        if (assignableTypes.size() <= 1) {
+            return; // no need to reduce
+        }
+        boolean removed;
+        do {
+            removed = false;
+            final Type type = assignableTypes.get(0);
+            for (int i = 1; i < assignableTypes.size(); i++) {
+                Type nextType = assignableTypes.get(i);
+                if (TypeUtils.isAssignable(nextType, type)) {
+                    assignableTypes.remove(0);
+                    i--;
+                    removed = true;
+                } else if (TypeUtils.isAssignable(type, nextType)) {
+                    assignableTypes.remove(i--);
+                    removed = true;
+                }
+            }
+        } while (removed && assignableTypes.size() > 1);
+
+    }
+
+    /**
+     * Given a set of {@link ConstraintValidator} implementation classes, map
+     * those to their target types.
+     * 
+     * @param constraintValidatorClasses
+     * @return {@link Map} of {@link Type} : {@link ConstraintValidator} subtype
+     */
+    private static <A extends Annotation> Map<Type, Class<? extends ConstraintValidator<A,
?>>> getValidatorsTypes(
+        Class<? extends ConstraintValidator<A, ?>>[] constraintValidatorClasses)
{
+        Map<Type, Class<? extends ConstraintValidator<A, ?>>> validatorsTypes
=
+            new HashMap<Type, Class<? extends ConstraintValidator<A, ?>>>();
+        for (Class<? extends ConstraintValidator<A, ?>> validatorType : constraintValidatorClasses)
{
+            Type validatedType =
+                TypeUtils.getTypeArguments(validatorType, ConstraintValidator.class).get(
+                    ConstraintValidator.class.getTypeParameters()[1]);
+            if (validatedType == null) {
+                throw new ValidationException(String.format("Could not detect validated type
for %s", validatorType));
+            }
+            if (validatedType instanceof GenericArrayType) {
+                Type componentType = TypeUtils.getArrayComponentType(validatedType);
+                if (componentType instanceof Class<?>) {
+                    validatedType = Array.newInstance((Class<?>) componentType, 0).getClass();
+                }
+            }
+            validatorsTypes.put(validatedType, validatorType);
+        }
+        return validatorsTypes;
+    }
+
+}

Propchange: incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/AnnotationProcessor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/AnnotationProcessor.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Modified: incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/Jsr303MetaBeanFactory.java
URL: http://svn.apache.org/viewvc/incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/Jsr303MetaBeanFactory.java?rev=993590&r1=993589&r2=993590&view=diff
==============================================================================
--- incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/Jsr303MetaBeanFactory.java
(original)
+++ incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/Jsr303MetaBeanFactory.java
Wed Sep  8 02:42:15 2010
@@ -18,33 +18,33 @@
  */
 package org.apache.bval.jsr303;
 
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.validation.Constraint;
+import javax.validation.GroupDefinitionException;
+import javax.validation.GroupSequence;
+import javax.validation.ValidationException;
+import javax.validation.groups.Default;
+
 import org.apache.bval.MetaBeanFactory;
 import org.apache.bval.jsr303.groups.Group;
 import org.apache.bval.jsr303.util.ClassHelper;
-import org.apache.bval.jsr303.util.ConstraintDefinitionValidator;
 import org.apache.bval.jsr303.util.SecureActions;
-import org.apache.bval.jsr303.util.TypeUtils;
 import org.apache.bval.jsr303.xml.MetaConstraint;
-import org.apache.bval.model.Features;
 import org.apache.bval.model.MetaBean;
 import org.apache.bval.model.MetaProperty;
 import org.apache.bval.util.AccessStrategy;
 import org.apache.bval.util.FieldAccess;
 import org.apache.bval.util.MethodAccess;
-import org.apache.commons.lang3.ArrayUtils;
-import org.apache.commons.lang3.ClassUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
-import javax.validation.*;
-import javax.validation.groups.Default;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.*;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
 /**
  * Description: process the class annotations for JSR303 constraint validations
  * to build the MetaBean with information from annotations and JSR303 constraint
@@ -62,20 +62,18 @@ public class Jsr303MetaBeanFactory imple
     protected final ApacheFactoryContext factoryContext;
 
     /**
+     * {@link AnnotationProcessor} used.
+     */
+    protected AnnotationProcessor annotationProcessor;
+
+    /**
      * Create a new Jsr303MetaBeanFactory instance.
      * 
      * @param factoryContext
      */
     public Jsr303MetaBeanFactory(ApacheFactoryContext factoryContext) {
         this.factoryContext = factoryContext;
-    }
-
-    private ConstraintValidatorFactory getConstraintValidatorFactory() {
-        return factoryContext.getConstraintValidatorFactory();
-    }
-
-    private ConstraintDefaults getDefaultConstraints() {
-        return factoryContext.getFactory().getDefaultConstraints();
+        this.annotationProcessor = new AnnotationProcessor(factoryContext);
     }
 
     /**
@@ -122,7 +120,8 @@ public class Jsr303MetaBeanFactory imple
 
         // if NOT ignore class level annotations
         if (!factoryContext.getFactory().getAnnotationIgnores().isIgnoreAnnotations(beanClass))
{
-            processAnnotations(null, beanClass, beanClass, null, new AppendValidationToMeta(metabean));
+            annotationProcessor.processAnnotations(null, beanClass, beanClass, null, new
AppendValidationToMeta(
+                metabean));
         }
 
         Field[] fields = beanClass.getDeclaredFields();
@@ -133,17 +132,13 @@ public class Jsr303MetaBeanFactory imple
             if (!factoryContext.getFactory().getAnnotationIgnores().isIgnoreAnnotations(field))
{
                 if (metaProperty == null) {
                     metaProperty = addMetaProperty(metabean, field.getName(), field.getGenericType());
-                    processAnnotations(metaProperty, beanClass, field, new FieldAccess(field),
-                        new AppendValidationToMeta(metaProperty));// ) {
-                } else {
-                    processAnnotations(metaProperty, beanClass, field, new FieldAccess(field),
-                        new AppendValidationToMeta(metaProperty));
                 }
+                annotationProcessor.processAnnotations(metaProperty, beanClass, field, new
FieldAccess(field),
+                    new AppendValidationToMeta(metaProperty));
             }
         }
         Method[] methods = beanClass.getDeclaredMethods();
         for (Method method : methods) {
-
             String propName = null;
             if (method.getParameterTypes().length == 0) {
                 propName = MethodAccess.getPropertyName(method);
@@ -155,12 +150,9 @@ public class Jsr303MetaBeanFactory imple
                     // not yet a MetaProperty
                     if (metaProperty == null) {
                         metaProperty = addMetaProperty(metabean, propName, method.getGenericReturnType());
-                        processAnnotations(metaProperty, beanClass, method, new MethodAccess(propName,
method),
-                            new AppendValidationToMeta(metaProperty));// ) {
-                    } else {
-                        processAnnotations(metaProperty, beanClass, method, new MethodAccess(propName,
method),
-                            new AppendValidationToMeta(metaProperty));
                     }
+                    annotationProcessor.processAnnotations(metaProperty, beanClass, method,
new MethodAccess(propName,
+                        method), new AppendValidationToMeta(metaProperty));
                 }
             } else if (hasValidationConstraintsDefined(method)) {
                 throw new ValidationException("Property " + method.getName() + " does not
follow javabean conventions.");
@@ -178,13 +170,12 @@ public class Jsr303MetaBeanFactory imple
      * @return <code>true</code> if constraints detected
      */
     protected boolean hasValidationConstraintsDefined(Method method) {
-        boolean ret = false;
         for (Annotation annot : method.getDeclaredAnnotations()) {
-            if (true == (ret = hasValidationConstraintsDefined(annot))) {
-                break;
+            if (hasValidationConstraintsDefined(annot)) {
+                return true;
             }
         }
-        return ret;
+        return false;
     }
 
     private boolean hasValidationConstraintsDefined(Annotation annot) {
@@ -192,7 +183,6 @@ public class Jsr303MetaBeanFactory imple
         if (annot.annotationType().getAnnotation(Constraint.class) != null) {
             return true;
         }
-        boolean ret = false;
 
         // Check in case it is a multivalued constraint
         Object value = null;
@@ -206,13 +196,12 @@ public class Jsr303MetaBeanFactory imple
 
         if (value instanceof Annotation[]) {
             for (Annotation annot2 : (Annotation[]) value) {
-                if (true == (ret = hasValidationConstraintsDefined(annot2))) {
-                    break;
+                if (hasValidationConstraintsDefined(annot2)) {
+                    return true;
                 }
             }
         }
-
-        return ret;
+        return false;
     }
 
     /**
@@ -223,7 +212,6 @@ public class Jsr303MetaBeanFactory imple
      * @throws IllegalAccessException
      * @throws InvocationTargetException
      */
-    @SuppressWarnings("unchecked")
     private void addXmlConstraints(Class<?> beanClass, MetaBean metabean) throws IllegalAccessException,
         InvocationTargetException {
         for (MetaConstraint<?, ? extends Annotation> meta : factoryContext.getFactory().getMetaConstraints(beanClass))
{
@@ -238,120 +226,16 @@ public class Jsr303MetaBeanFactory imple
                             .getJavaType());
                 }
             }
-            Class<? extends ConstraintValidator<? extends Annotation, ?>>[] validatorClasses
=
-                findConstraintValidatorClasses(meta.getAnnotation(), null);
-            applyConstraint((Annotation) meta.getAnnotation(),
-                (Class<? extends ConstraintValidator<Annotation, ?>>[]) validatorClasses,
metaProperty, beanClass, meta
-                    .getAccessStrategy(), new AppendValidationToMeta(metaProperty == null
? metabean : metaProperty));
+            annotationProcessor.processAnnotation(meta.getAnnotation(), metaProperty, beanClass,
meta
+                .getAccessStrategy(), new AppendValidationToMeta(metaProperty == null ? metabean
: metaProperty));
         }
         for (AccessStrategy access : factoryContext.getFactory().getValidAccesses(beanClass))
{
             MetaProperty metaProperty = metabean.getProperty(access.getPropertyName());
             if (metaProperty == null) {
                 metaProperty = addMetaProperty(metabean, access.getPropertyName(), access.getJavaType());
             }
-            processValid(metaProperty, access);
-        }
-    }
-
-    private MetaProperty addMetaProperty(MetaBean parentMetaBean, String propName, Type type)
{
-        MetaProperty metaProperty;
-        metaProperty = new MetaProperty();
-        metaProperty.setName(propName);
-        metaProperty.setType(type);
-        parentMetaBean.putProperty(propName, metaProperty);
-        return metaProperty;
-    }
-
-    private boolean processAnnotations(MetaProperty prop, Class<?> owner, AnnotatedElement
element,
-        AccessStrategy access, AppendValidation appender) throws IllegalAccessException,
InvocationTargetException {
-
-        boolean changed = false;
-        for (Annotation annotation : element.getDeclaredAnnotations()) {
-            changed |= processAnnotation(annotation, prop, owner, access, appender);
-        }
-        return changed;
-    }
-
-    private <A extends Annotation> boolean processAnnotation(A annotation, MetaProperty
prop, Class<?> owner,
-        AccessStrategy access, AppendValidation appender) throws IllegalAccessException,
InvocationTargetException {
-        if (annotation instanceof Valid) {
-            return processValid(prop, access);
-        } else {
-            /**
-             * An annotation is considered a constraint definition if its
-             * retention policy contains RUNTIME and if the annotation itself is
-             * annotated with javax.validation.Constraint.
-             */
-            Constraint vcAnno = annotation.annotationType().getAnnotation(Constraint.class);
-            if (vcAnno != null) {
-                ConstraintDefinitionValidator.validateConstraintDefinition(annotation);
-                Class<? extends ConstraintValidator<A, ?>>[] validatorClasses;
-                validatorClasses = findConstraintValidatorClasses(annotation, vcAnno);
-                return applyConstraint(annotation, validatorClasses, prop, owner, access,
appender);
-            } else {
-                /**
-                 * Multi-valued constraints: To support this requirement, the
-                 * bean validation provider treats regular annotations
-                 * (annotations not annotated by @Constraint) whose value
-                 * element has a return type of an array of constraint
-                 * annotations in a special way.
-                 */
-                Object result = SecureActions.getAnnotationValue(annotation, ANNOTATION_VALUE);
-                if (result != null && result instanceof Annotation[]) {
-                    boolean changed = false;
-                    for (Annotation each : (Annotation[]) result) {
-                        changed |= processAnnotation(each, prop, owner, access, appender);
-                    }
-                    return changed;
-                }
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Find available {@link ConstraintValidation} classes for a given
-     * constraint annotation.
-     * 
-     * @param annotation
-     * @param vcAnno
-     * @return {@link ConstraintValidation} implementation class array
-     */
-    @SuppressWarnings("unchecked")
-    protected <A extends Annotation> Class<? extends ConstraintValidator<A, ?>>[]
findConstraintValidatorClasses(
-        A annotation, Constraint vcAnno) {
-        if (vcAnno == null) {
-            vcAnno = annotation.annotationType().getAnnotation(Constraint.class);
-        }
-        Class<? extends ConstraintValidator<A, ?>>[] validatorClasses;
-        Class<A> annotationType = (Class<A>) annotation.annotationType();
-        validatorClasses = factoryContext.getFactory().getConstraintsCache().getConstraintValidators(annotationType);
-        if (validatorClasses == null) {
-            validatorClasses = (Class<? extends ConstraintValidator<A, ?>>[])
vcAnno.validatedBy();
-            if (validatorClasses.length == 0) {
-                validatorClasses = getDefaultConstraints().getValidatorClasses(annotationType);
-            }
+            annotationProcessor.addAccessStrategy(metaProperty, access);
         }
-        return validatorClasses;
-    }
-
-    private boolean processValid(MetaProperty prop, AccessStrategy access) {
-        if (prop != null/* && prop.getMetaBean() == null */) {
-            AccessStrategy[] strategies = prop.getFeature(Features.Property.REF_CASCADE);
-            if (strategies == null) {
-                strategies = new AccessStrategy[] { access };
-                prop.putFeature(Features.Property.REF_CASCADE, strategies);
-            } else {
-                if (!ArrayUtils.contains(strategies, access)) {
-                    AccessStrategy[] strategies_new = new AccessStrategy[strategies.length
+ 1];
-                    System.arraycopy(strategies, 0, strategies_new, 0, strategies.length);
-                    strategies_new[strategies.length] = access;
-                    prop.putFeature(Features.Property.REF_CASCADE, strategies_new);
-                }
-            }
-            return true;
-        }
-        return false;
     }
 
     private void processGroupSequence(Class<?> beanClass, MetaBean metabean) {
@@ -394,191 +278,13 @@ public class Jsr303MetaBeanFactory imple
         }
     }
 
-    /**
-     * Apply a constraint to the specified <code>appender</code>.
-     * 
-     * @param annotation
-     *            constraint annotation
-     * @param constraintClasses
-     *            known {@link ConstraintValidator} implementation classes for
-     *            <code>annotation</code>
-     * @param prop
-     *            meta-property
-     * @param owner
-     *            type
-     * @param access
-     *            strategy
-     * @param appender
-     * @return success flag
-     * @throws IllegalAccessException
-     * @throws InvocationTargetException
-     */
-    protected <A extends Annotation> boolean applyConstraint(A annotation,
-        Class<? extends ConstraintValidator<A, ?>>[] constraintClasses, MetaProperty
prop, Class<?> owner,
-        AccessStrategy access, AppendValidation appender) throws IllegalAccessException,
InvocationTargetException {
-
-        final ConstraintValidator<A, ?> validator;
-        if (constraintClasses != null && constraintClasses.length > 0) {
-            Type type = determineTargetedType(owner, access);
-            /**
-             * spec says in chapter 3.5.3.: The ConstraintValidator chosen to
-             * validate a declared type T is the one where the type supported by
-             * the ConstraintValidator is a supertype of T and where there is no
-             * other ConstraintValidator whose supported type is a supertype of
-             * T and not a supertype of the chosen ConstraintValidator supported
-             * type.
-             */
-            Map<Type, Class<? extends ConstraintValidator<A, ?>>> validatorTypes
=
-                (Map<Type, Class<? extends ConstraintValidator<A, ?>>>)
TypeUtils.getValidatorsTypes(constraintClasses);
-            final List<Type> assignableTypes = new ArrayList<Type>(constraintClasses.length);
-            fillAssignableTypes(type, validatorTypes.keySet(), assignableTypes);
-            reduceAssignableTypes(assignableTypes);
-            checkOneType(assignableTypes, type, owner, annotation, access);
-            validator = getConstraintValidatorFactory().getInstance(validatorTypes.get(assignableTypes.get(0)));
-            if (validator == null) {
-                throw new ValidationException("Factory returned null validator for: "
-                    + validatorTypes.get(assignableTypes.get(0)));
-            }
-            // NOTE: validator initialization deferred until append phase
-        } else {
-            validator = null;
-        }
-        final AnnotationConstraintBuilder<A> builder =
-            new AnnotationConstraintBuilder<A>(constraintClasses, validator, annotation,
owner, access);
-
-        // JSR-303 3.4.4: Add implicit groups
-        if (prop != null && prop.getParentMetaBean() != null) {
-            MetaBean parentMetaBean = prop.getParentMetaBean();
-            // If:
-            // - the owner is an interface
-            // - the class of the metabean being build is different than the
-            // owner
-            // - and only the Default group is defined
-            // Then: add the owner interface as implicit groups
-            if (builder.getConstraintValidation().getOwner().isInterface()
-                && parentMetaBean.getBeanClass() != builder.getConstraintValidation().getOwner()
-                && builder.getConstraintValidation().getGroups().size() == 1
-                && builder.getConstraintValidation().getGroups().contains(Default.class))
{
-                Set<Class<?>> groups = builder.getConstraintValidation().getGroups();
-                groups.add(builder.getConstraintValidation().getOwner());
-                builder.getConstraintValidation().setGroups(groups);
-            }
-        }
-
-        // If already building a constraint composition tree, ensure that:
-        // - the parent groups are inherited
-        // - the parent payload is inherited
-        if (appender instanceof AppendValidationToBuilder) {
-            AppendValidationToBuilder avb = (AppendValidationToBuilder) appender;
-            builder.getConstraintValidation().setGroups(avb.getInheritedGroups());
-            builder.getConstraintValidation().setPayload(avb.getInheritedPayload());
-        }
-
-        // process composed constraints:
-        // here are not other superclasses possible, because annotations do not
-        // inherit!
-        processAnnotations(prop, owner, annotation.annotationType(), access, new AppendValidationToBuilder(builder));
-
-        // Even if the validator is null, it must be added to mimic the RI impl
-        appender.append(builder.getConstraintValidation());
-        return true;
-    }
-
-    private void checkOneType(List<Type> types, Type targetType, Class<?> owner,
Annotation anno, AccessStrategy access) {
-
-        if (types.isEmpty()) {
-            StringBuilder buf =
-                new StringBuilder().append("No validator could be found for type ").append(stringForType(targetType))
-                    .append(". See: @").append(anno.annotationType().getSimpleName()).append("
at ").append(
-                        stringForLocation(owner, access));
-            throw new UnexpectedTypeException(buf.toString());
-        } else if (types.size() > 1) {
-            StringBuilder buf = new StringBuilder();
-            buf.append("Ambiguous validators for type ");
-            buf.append(stringForType(targetType));
-            buf.append(". See: @").append(anno.annotationType().getSimpleName()).append("
at ").append(
-                stringForLocation(owner, access));
-            buf.append(". Validators are: ");
-            boolean comma = false;
-            for (Type each : types) {
-                if (comma)
-                    buf.append(", ");
-                comma = true;
-                buf.append(each);
-            }
-            throw new UnexpectedTypeException(buf.toString());
-        }
-    }
-
-    /** implements spec chapter 3.5.3. ConstraintValidator resolution algorithm. */
-    private Type determineTargetedType(Class<?> owner, AccessStrategy access) {
-        // if the constraint declaration is hosted on a class or an interface,
-        // the targeted type is the class or the interface.
-        if (access == null)
-            return owner;
-        Type type = access.getJavaType();
-        if (type == null)
-            return Object.class;
-        if (type instanceof Class<?>)
-            type = ClassUtils.primitiveToWrapper((Class<?>) type);
-        return type;
-    }
-
-    private String stringForType(Type clazz) {
-        if (clazz instanceof Class<?>) {
-            if (((Class<?>) clazz).isArray()) {
-                return ((Class<?>) clazz).getComponentType().getName() + "[]";
-            } else {
-                return ((Class<?>) clazz).getName();
-            }
-        } else {
-            return clazz.toString();
-        }
-    }
-
-    private String stringForLocation(Class<?> owner, AccessStrategy access) {
-        if (access != null) {
-            return access.toString();
-        } else {
-            return owner.getName();
-        }
-    }
-
-    private void fillAssignableTypes(Type type, Set<Type> validatorsTypes, List<Type>
suitableTypes) {
-        for (Type validatorType : validatorsTypes) {
-            if (TypeUtils.isAssignable(validatorType, type) && !suitableTypes.contains(validatorType))
{
-                suitableTypes.add(validatorType);
-            }
-        }
+    private static MetaProperty addMetaProperty(MetaBean parentMetaBean, String propName,
Type type) {
+        MetaProperty metaProperty;
+        metaProperty = new MetaProperty();
+        metaProperty.setName(propName);
+        metaProperty.setType(type);
+        parentMetaBean.putProperty(propName, metaProperty);
+        return metaProperty;
     }
 
-    /**
-     * Tries to reduce all assignable classes down to a single class.
-     * 
-     * @param assignableTypes
-     *            The set of all classes which are assignable to the class of
-     *            the value to be validated and which are handled by at least
-     *            one of the validators for the specified constraint.
-     */
-    private void reduceAssignableTypes(List<Type> assignableTypes) {
-        if (assignableTypes.size() <= 1) {
-            return; // no need to reduce
-        }
-        boolean removed;
-        do {
-            removed = false;
-            final Type type = assignableTypes.get(0);
-            for (int i = 1; i < assignableTypes.size(); i++) {
-                Type nextType = assignableTypes.get(i);
-                if (TypeUtils.isAssignable(type, nextType)) {
-                    assignableTypes.remove(0);
-                    i--;
-                    removed = true;
-                } else if (TypeUtils.isAssignable(nextType, type)) {
-                    assignableTypes.remove(i--);
-                    removed = true;
-                }
-            }
-        } while (removed && assignableTypes.size() > 1);
-    }
 }

Modified: incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/extensions/MethodValidatorMetaBeanFactory.java
URL: http://svn.apache.org/viewvc/incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/extensions/MethodValidatorMetaBeanFactory.java?rev=993590&r1=993589&r2=993590&view=diff
==============================================================================
--- incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/extensions/MethodValidatorMetaBeanFactory.java
(original)
+++ incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/extensions/MethodValidatorMetaBeanFactory.java
Wed Sep  8 02:42:15 2010
@@ -26,7 +26,6 @@ import org.apache.bval.util.AccessStrate
 import org.apache.commons.lang3.ClassUtils;
 
 import javax.validation.Constraint;
-import javax.validation.ConstraintValidator;
 import javax.validation.Valid;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Constructor;
@@ -158,9 +157,7 @@ public class MethodValidatorMetaBeanFact
     } else {
       Constraint vcAnno = annotation.annotationType().getAnnotation(Constraint.class);
       if (vcAnno != null) {
-        Class<? extends ConstraintValidator<A, ?>>[] validatorClasses;
-        validatorClasses = findConstraintValidatorClasses(annotation, vcAnno);
-        applyConstraint(annotation, validatorClasses, null,
+        annotationProcessor.processAnnotation(annotation, null,
             ClassUtils.primitiveToWrapper((Class<?>) access.getJavaType()), access,
validations);
       } else {
         /**



Mime
View raw message