[hibernate-commits] Hibernate SVN: r18897 - in validator/trunk/hibernate-validator-annotation-processor/src: main/java/org/hibernate/validator/ap/util and 6 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Thu Feb 25 14:12:36 EST 2010


Author: hardy.ferentschik
Date: 2010-02-25 14:12:35 -0500 (Thu, 25 Feb 2010)
New Revision: 18897

Added:
   validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/MultipleConstraintsOfSameType.java
   validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/nouniquevalidatorresolution/NoUniqueValidatorResolution.java
   validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/nouniquevalidatorresolution/SerializableCollection.java
   validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/nouniquevalidatorresolution/Size.java
   validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/nouniquevalidatorresolution/SizeValidatorForCollection.java
   validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/nouniquevalidatorresolution/SizeValidatorForSerializable.java
   validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/nouniquevalidatorresolution/SizeValidatorForSet.java
Modified:
   validator/trunk/hibernate-validator-annotation-processor/src/main/java/org/hibernate/validator/ap/ConstraintAnnotationVisitor.java
   validator/trunk/hibernate-validator-annotation-processor/src/main/java/org/hibernate/validator/ap/ConstraintValidationProcessor.java
   validator/trunk/hibernate-validator-annotation-processor/src/main/java/org/hibernate/validator/ap/util/AnnotationApiHelper.java
   validator/trunk/hibernate-validator-annotation-processor/src/main/java/org/hibernate/validator/ap/util/ConstraintHelper.java
   validator/trunk/hibernate-validator-annotation-processor/src/main/resources/org/hibernate/validator/ap/ValidationProcessorMessages.properties
   validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/ConstraintValidationProcessorTest.java
   validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/FieldLevelValidationUsingBuiltInConstraints.java
   validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/invalidcomposedconstraint/ValidCustomerNumber.java
   validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testutil/CompilerTestHelper.java
Log:
HV-269
Applying Gunnar's latest patch for this annotation processor.

Modified: validator/trunk/hibernate-validator-annotation-processor/src/main/java/org/hibernate/validator/ap/ConstraintAnnotationVisitor.java
===================================================================
--- validator/trunk/hibernate-validator-annotation-processor/src/main/java/org/hibernate/validator/ap/ConstraintAnnotationVisitor.java	2010-02-25 19:04:40 UTC (rev 18896)
+++ validator/trunk/hibernate-validator-annotation-processor/src/main/java/org/hibernate/validator/ap/ConstraintAnnotationVisitor.java	2010-02-25 19:12:35 UTC (rev 18897)
@@ -1,4 +1,4 @@
-// $Id: ConstraintAnnotationVisitor.java 17946 2009-11-06 18:23:48Z hardy.ferentschik $
+// $Id$
 /*
 * JBoss, Home of Professional Open Source
 * Copyright 2009, Red Hat Middleware LLC, and individual contributors
@@ -30,9 +30,10 @@
 import javax.lang.model.element.VariableElement;
 import javax.lang.model.util.ElementKindVisitor6;
 import javax.tools.Diagnostic.Kind;
-import javax.validation.Constraint;
 
+import org.hibernate.validator.ap.util.AnnotationApiHelper;
 import org.hibernate.validator.ap.util.ConstraintHelper;
+import org.hibernate.validator.ap.util.ConstraintHelper.ConstraintCheckResult;
 
 /**
  * An {@link ElementVisitor} that visits elements (type declarations, methods
@@ -42,25 +43,75 @@
  * @author Gunnar Morling.
  */
 final class ConstraintAnnotationVisitor extends ElementKindVisitor6<Void, List<AnnotationMirror>> {
+
+	/**
+	 * The name of the processor option for setting the diagnostic kind to be
+	 * used when reporting errors during annotation processing. Can be set on
+	 * the command line using the -A option, e.g.
+	 * <code>-AdiagnosticKind=ERROR</code>.
+	 */
+	public final static String DIAGNOSTIC_KIND_PROCESSOR_OPTION_NAME = "diagnosticKind";
+
+	/**
+	 * The diagnostic kind to be used if no or an invalid kind is given as processor option.
+	 */
+	public final static Kind DEFAULT_DIAGNOSTIC_KIND = Kind.ERROR;
+
+	/**
+	 * The kind of diagnostic to be used when reporting any problems.
+	 */
+	private Kind diagnosticKind;
+
 	private final ProcessingEnvironment processingEnvironment;
 
 	private final ResourceBundle errorMessages;
 
-	//TODO GM: make configurable using Options API
-	private final Kind messagingKind = Kind.ERROR;
-
 	private final ConstraintHelper constraintHelper;
 
+	private final AnnotationApiHelper annotationApiHelper;
+
 	public ConstraintAnnotationVisitor(ProcessingEnvironment processingEnvironment) {
 
 		this.processingEnvironment = processingEnvironment;
 
 		errorMessages = ResourceBundle.getBundle( "org.hibernate.validator.ap.ValidationProcessorMessages" );
-		constraintHelper = new ConstraintHelper(
+
+		annotationApiHelper = new AnnotationApiHelper(
 				processingEnvironment.getElementUtils(), processingEnvironment.getTypeUtils()
 		);
+
+		constraintHelper = new ConstraintHelper(
+				processingEnvironment.getElementUtils(), processingEnvironment.getTypeUtils(), annotationApiHelper
+		);
+
+		initializeDiagnosticKind();
 	}
 
+	private void initializeDiagnosticKind() {
+
+		String diagnosticKindFromOptions = processingEnvironment.getOptions()
+				.get( DIAGNOSTIC_KIND_PROCESSOR_OPTION_NAME );
+
+		if ( diagnosticKindFromOptions != null ) {
+			try {
+				diagnosticKind = Kind.valueOf( diagnosticKindFromOptions );
+			}
+			catch ( IllegalArgumentException e ) {
+
+				processingEnvironment.getMessager().printMessage(
+						Kind.ERROR, MessageFormat.format(
+								errorMessages.getString( "INVALID_DIAGNOSTIC_KIND_GIVEN" ), diagnosticKindFromOptions
+						)
+				);
+
+				diagnosticKind = DEFAULT_DIAGNOSTIC_KIND;
+			}
+		}
+		else {
+			diagnosticKind = DEFAULT_DIAGNOSTIC_KIND;
+		}
+	}
+
 	/**
 	 * <p>
 	 * Checks whether the given mirrors representing one or more constraint annotations are correctly
@@ -78,33 +129,22 @@
 	 * </ul>
 	 */
 	@Override
-	public Void visitExecutableAsMethod(ExecutableElement element,
+	public Void visitExecutableAsMethod(ExecutableElement method,
 										List<AnnotationMirror> mirrors) {
 
 		for ( AnnotationMirror oneAnnotationMirror : mirrors ) {
 
-			if ( !isJavaBeanGetterName( element.getSimpleName().toString() ) ||
-					hasParameters( element ) ) {
+			if ( constraintHelper.isConstraintAnnotation( oneAnnotationMirror ) ) {
 
-				reportError( element, oneAnnotationMirror, "ONLY_GETTERS_MAY_BE_ANNOTATED" );
-
-				continue;
+				checkConstraintAtMethod( method, oneAnnotationMirror );
 			}
-
-			if ( isStaticMethod( element ) ) {
-
-				reportError( element, oneAnnotationMirror, "STATIC_METHODS_MAY_NOT_BE_ANNOTATED" );
-
-				continue;
+			else if ( constraintHelper.isMultiValuedConstraint( oneAnnotationMirror ) ) {
+				for ( AnnotationMirror onePartOfMultiValuedConstraint : constraintHelper.getPartsOfMultiValuedConstraint(
+						oneAnnotationMirror
+				) ) {
+					checkConstraintAtMethod( method, onePartOfMultiValuedConstraint );
+				}
 			}
-
-			if ( !constraintHelper.isAnnotationAllowedAtMethod( oneAnnotationMirror.getAnnotationType(), element ) ) {
-
-				reportError(
-						element, oneAnnotationMirror, "NOT_SUPPORTED_RETURN_TYPE",
-						oneAnnotationMirror.getAnnotationType().asElement().getSimpleName()
-				);
-			}
 		}
 		return null;
 	}
@@ -117,6 +157,9 @@
 	 * <li>
 	 * The type of the field must be supported by the constraints.
 	 * </li>
+	 * <li>
+	 * The field must not be static.
+	 * </li>
 	 * </ul>
 	 */
 	@Override
@@ -124,15 +167,17 @@
 
 		for ( AnnotationMirror oneAnnotationMirror : mirrors ) {
 
-			if ( !constraintHelper.isAnnotationAllowedAtField(
-					oneAnnotationMirror.getAnnotationType(), annotatedField
-			) ) {
+			if ( constraintHelper.isConstraintAnnotation( oneAnnotationMirror ) ) {
 
-				reportError(
-						annotatedField, oneAnnotationMirror, "NOT_SUPPORTED_TYPE",
-						oneAnnotationMirror.getAnnotationType().asElement().getSimpleName()
-				);
+				checkConstraintAtField( annotatedField, oneAnnotationMirror );
 			}
+			else if ( constraintHelper.isMultiValuedConstraint( oneAnnotationMirror ) ) {
+				for ( AnnotationMirror onePartOfMultiValuedConstraint : constraintHelper.getPartsOfMultiValuedConstraint(
+						oneAnnotationMirror
+				) ) {
+					checkConstraintAtField( annotatedField, onePartOfMultiValuedConstraint );
+				}
+			}
 		}
 
 		return null;
@@ -147,15 +192,32 @@
 	 * declarations.
 	 * </p>
 	 */
+	// TODO GM: do a more complete check of constraint annotation type
+	// declarations:
+	// 
+	// - check, existence of groups(), message(), payload()
+	// - check, retention policy
+	// - check, that the set of supported types is not empty
+	// - optionally check, that validated types resolve to non-parametrized types
 	@Override
-	public Void visitTypeAsAnnotationType(TypeElement e,
+	public Void visitTypeAsAnnotationType(TypeElement annotationType,
 										  List<AnnotationMirror> mirrors) {
 
-		if ( !isConstraintAnnotation( e ) ) {
+		for ( AnnotationMirror oneAnnotationMirror : mirrors ) {
 
-			for ( AnnotationMirror oneAnnotationMirror : mirrors ) {
-				reportError( e, oneAnnotationMirror, "ONLY_CONSTRAINT_ANNOTATIONS_MAY_BE_ANNOTATED" );
+			if ( constraintHelper.isConstraintAnnotation( oneAnnotationMirror ) ) {
+
+				checkConstraintAtAnnotationType( annotationType, oneAnnotationMirror );
+
 			}
+			else if ( constraintHelper.isMultiValuedConstraint( oneAnnotationMirror ) ) {
+
+				for ( AnnotationMirror onePartOfMultiValuedConstraint : constraintHelper.getPartsOfMultiValuedConstraint(
+						oneAnnotationMirror
+				) ) {
+					checkConstraintAtAnnotationType( annotationType, onePartOfMultiValuedConstraint );
+				}
+			}
 		}
 
 		return null;
@@ -185,20 +247,91 @@
 
 		for ( AnnotationMirror oneAnnotationMirror : mirrors ) {
 
-			if ( !constraintHelper.isAnnotationAllowedAtType(
-					oneAnnotationMirror.getAnnotationType(), annotatedType
-			) ) {
+			if ( constraintHelper.isConstraintAnnotation( oneAnnotationMirror ) ) {
 
-				reportError(
-						annotatedType, oneAnnotationMirror, "NOT_SUPPORTED_TYPE",
-						oneAnnotationMirror.getAnnotationType().asElement().getSimpleName()
-				);
+				checkConstraintAtType( annotatedType, oneAnnotationMirror );
 			}
+			else if ( constraintHelper.isMultiValuedConstraint( oneAnnotationMirror ) ) {
+				for ( AnnotationMirror onePartOfMultiValuedConstraint : constraintHelper.getPartsOfMultiValuedConstraint(
+						oneAnnotationMirror
+				) ) {
+					checkConstraintAtType( annotatedType, onePartOfMultiValuedConstraint );
+				}
+			}
 		}
 
 		return null;
 	}
 
+	private void checkConstraintAtType(TypeElement annotatedType, AnnotationMirror mirror) {
+
+		if ( constraintHelper.checkConstraint(
+				mirror.getAnnotationType(), annotatedType.asType()
+		) != ConstraintCheckResult.ALLOWED ) {
+
+			reportError(
+					annotatedType, mirror, "NOT_SUPPORTED_TYPE",
+					mirror.getAnnotationType().asElement().getSimpleName()
+			);
+		}
+	}
+
+	private void checkConstraintAtField(VariableElement annotatedField, AnnotationMirror annotationMirror) {
+
+		if ( isStaticElement( annotatedField ) ) {
+
+			reportError( annotatedField, annotationMirror, "STATIC_FIELDS_MAY_NOT_BE_ANNOTATED" );
+
+			return;
+		}
+
+		if ( constraintHelper.checkConstraint(
+				annotationMirror.getAnnotationType(), annotatedField.asType()
+		) != ConstraintCheckResult.ALLOWED ) {
+
+			reportError(
+					annotatedField, annotationMirror, "NOT_SUPPORTED_TYPE",
+					annotationMirror.getAnnotationType().asElement().getSimpleName()
+			);
+		}
+	}
+
+	private void checkConstraintAtMethod(ExecutableElement method, AnnotationMirror mirror) {
+
+		if ( !isJavaBeanGetterName( method.getSimpleName().toString() ) ||
+				hasParameters( method ) ) {
+
+			reportError( method, mirror, "ONLY_GETTERS_MAY_BE_ANNOTATED" );
+
+			return;
+		}
+
+		if ( isStaticElement( method ) ) {
+
+			reportError( method, mirror, "STATIC_METHODS_MAY_NOT_BE_ANNOTATED" );
+
+			return;
+		}
+
+		if ( constraintHelper.checkConstraint(
+				mirror.getAnnotationType(), method.getReturnType()
+		) != ConstraintCheckResult.ALLOWED ) {
+
+			reportError(
+					method, mirror, "NOT_SUPPORTED_RETURN_TYPE",
+					mirror.getAnnotationType().asElement().getSimpleName()
+			);
+		}
+	}
+
+	private void checkConstraintAtAnnotationType(TypeElement annotationType, AnnotationMirror annotationMirror) {
+
+		if ( !constraintHelper.isConstraintAnnotation( annotationType ) ) {
+			reportError( annotationType, annotationMirror, "ONLY_CONSTRAINT_ANNOTATIONS_MAY_BE_ANNOTATED" );
+		}
+
+	}
+
 	private boolean hasParameters(ExecutableElement method) {
 		return !method.getParameters().isEmpty();
 	}
@@ -207,14 +340,10 @@
 		return methodName.startsWith( "is" ) || methodName.startsWith( "has" ) || methodName.startsWith( "get" );
 	}
 
-	private boolean isStaticMethod(ExecutableElement method) {
-		return method.getModifiers().contains( Modifier.STATIC );
+	private boolean isStaticElement(Element element) {
+		return element.getModifiers().contains( Modifier.STATIC );
 	}
 
-	private boolean isConstraintAnnotation(TypeElement e) {
-		return e.getAnnotation( Constraint.class ) != null;
-	}
-
 	/**
 	 * Reports an error at the given location using the given message key and
 	 * optionally the given message parameters.
@@ -237,7 +366,7 @@
 		}
 
 		processingEnvironment.getMessager().printMessage(
-				messagingKind, message, element, annotationMirror
+				diagnosticKind, message, element, annotationMirror
 		);
 	}
 


Property changes on: validator/trunk/hibernate-validator-annotation-processor/src/main/java/org/hibernate/validator/ap/ConstraintAnnotationVisitor.java
___________________________________________________________________
Name: svn:keywords
   + Id

Modified: validator/trunk/hibernate-validator-annotation-processor/src/main/java/org/hibernate/validator/ap/ConstraintValidationProcessor.java
===================================================================
--- validator/trunk/hibernate-validator-annotation-processor/src/main/java/org/hibernate/validator/ap/ConstraintValidationProcessor.java	2010-02-25 19:04:40 UTC (rev 18896)
+++ validator/trunk/hibernate-validator-annotation-processor/src/main/java/org/hibernate/validator/ap/ConstraintValidationProcessor.java	2010-02-25 19:12:35 UTC (rev 18897)
@@ -1,4 +1,4 @@
-// $Id: ConstraintValidationProcessor.java 17946 2009-11-06 18:23:48Z hardy.ferentschik $
+// $Id$
 /*
 * JBoss, Home of Professional Open Source
 * Copyright 2009, Red Hat Middleware LLC, and individual contributors
@@ -22,6 +22,7 @@
 import javax.annotation.processing.AbstractProcessor;
 import javax.annotation.processing.RoundEnvironment;
 import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.annotation.processing.SupportedOptions;
 import javax.annotation.processing.SupportedSourceVersion;
 import javax.lang.model.SourceVersion;
 import javax.lang.model.element.AnnotationMirror;
@@ -30,23 +31,35 @@
 import javax.lang.model.element.TypeElement;
 
 import org.hibernate.validator.ap.util.AnnotationApiHelper;
-import org.hibernate.validator.ap.util.ConstraintHelper;
 
 /**
- * Annotation processor for validating Bean Validation constraints.
+ * An annotation processor for checking <a
+ * href="http://jcp.org/en/jsr/detail?id=303">Bean Validation</a> constraints.
+ * The processor supports the following options:
+ * <ul>
+ * <li><code>diagnosticKind</code>: the severity with which any occured problems
+ * shall be reported. Must be given in form of the string representation of a
+ * value from {@link javax.tools.Diagnostic.Kind}, e.g.
+ * "diagnosticKind=WARNING". Default is Kind.ERROR.</li>
+ * <li>TODO GM: validationMode: whether spec compliance shall be checked
+ * strictly or loosely (e.g. by allowing validators for parametrized types)</li>
+ * </ul>
  *
  * @author Hardy Ferentschik
  * @author Gunnar Morling
  */
+// TODO GM: check @Valid annotation
+// TODO GM: add documentation for AP to HV reference guide
 @SupportedAnnotationTypes("*")
 @SupportedSourceVersion(SourceVersion.RELEASE_6)
+ at SupportedOptions(ConstraintAnnotationVisitor.DIAGNOSTIC_KIND_PROCESSOR_OPTION_NAME)
 public class ConstraintValidationProcessor extends AbstractProcessor {
+
 	/**
 	 * Whether this processor claims all processed annotations exclusively or not.
 	 */
 	private static final boolean ANNOTATIONS_CLAIMED_EXCLUSIVELY = false;
 
-
 	@Override
 	public boolean process(
 			final Set<? extends TypeElement> annotations,
@@ -55,18 +68,11 @@
 		AnnotationApiHelper typeHelper = new AnnotationApiHelper(
 				processingEnv.getElementUtils(), processingEnv.getTypeUtils()
 		);
+
 		ElementVisitor<Void, List<AnnotationMirror>> visitor = new ConstraintAnnotationVisitor( processingEnv );
-		ConstraintHelper constraintHelper = new ConstraintHelper(
-				processingEnv.getElementUtils(), processingEnv.getTypeUtils()
-		);
 
 		for ( TypeElement oneAnnotation : annotations ) {
 
-			//only constraint annotations are relevant
-			if ( !constraintHelper.isConstraintAnnotation( oneAnnotation ) ) {
-				continue;
-			}
-
 			Set<? extends Element> elementsWithConstraintAnnotation =
 					roundEnvironment.getElementsAnnotatedWith( oneAnnotation );
 
@@ -81,4 +87,5 @@
 
 		return ANNOTATIONS_CLAIMED_EXCLUSIVELY;
 	}
+
 }


Property changes on: validator/trunk/hibernate-validator-annotation-processor/src/main/java/org/hibernate/validator/ap/ConstraintValidationProcessor.java
___________________________________________________________________
Name: svn:keywords
   + Id

Modified: validator/trunk/hibernate-validator-annotation-processor/src/main/java/org/hibernate/validator/ap/util/AnnotationApiHelper.java
===================================================================
--- validator/trunk/hibernate-validator-annotation-processor/src/main/java/org/hibernate/validator/ap/util/AnnotationApiHelper.java	2010-02-25 19:04:40 UTC (rev 18896)
+++ validator/trunk/hibernate-validator-annotation-processor/src/main/java/org/hibernate/validator/ap/util/AnnotationApiHelper.java	2010-02-25 19:12:35 UTC (rev 18897)
@@ -1,4 +1,4 @@
-// $Id: ConstraintHelper.java 17946 2009-11-06 18:23:48Z hardy.ferentschik $
+// $Id$
 /*
 * JBoss, Home of Professional Open Source
 * Copyright 2009, Red Hat Middleware LLC, and individual contributors
@@ -18,82 +18,254 @@
 package org.hibernate.validator.ap.util;
 
 import java.lang.annotation.Annotation;
-import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
-
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
 import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.ExecutableElement;
 import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeKind;
 import javax.lang.model.type.TypeMirror;
 import javax.lang.model.util.Elements;
+import javax.lang.model.util.SimpleAnnotationValueVisitor6;
 import javax.lang.model.util.Types;
 
 /**
  * A helper class providing some useful methods to work with types
  * from the JSR-269-API.
- * 
+ *
  * @author Gunnar Morling
- *
  */
 public class AnnotationApiHelper {
 
 	private Elements elementUtils;
-	
+
 	private Types typeUtils;
 
+	private final Map<Class<?>, TypeMirror> primitiveMirrors;
+
 	public AnnotationApiHelper(Elements elementUtils, Types typeUtils) {
 
 		this.elementUtils = elementUtils;
 		this.typeUtils = typeUtils;
+
+		Map<Class<?>, TypeMirror> tempPrimitiveMirrors = CollectionHelper.newHashMap();
+
+		tempPrimitiveMirrors.put( Boolean.TYPE, typeUtils.getPrimitiveType( TypeKind.BOOLEAN ) );
+		tempPrimitiveMirrors.put( Character.TYPE, typeUtils.getPrimitiveType( TypeKind.CHAR ) );
+		tempPrimitiveMirrors.put( Byte.TYPE, typeUtils.getPrimitiveType( TypeKind.BYTE ) );
+		tempPrimitiveMirrors.put( Short.TYPE, typeUtils.getPrimitiveType( TypeKind.SHORT ) );
+		tempPrimitiveMirrors.put( Integer.TYPE, typeUtils.getPrimitiveType( TypeKind.INT ) );
+		tempPrimitiveMirrors.put( Long.TYPE, typeUtils.getPrimitiveType( TypeKind.LONG ) );
+		tempPrimitiveMirrors.put( Float.TYPE, typeUtils.getPrimitiveType( TypeKind.FLOAT ) );
+		tempPrimitiveMirrors.put( Double.TYPE, typeUtils.getPrimitiveType( TypeKind.DOUBLE ) );
+
+		primitiveMirrors = Collections.unmodifiableMap( tempPrimitiveMirrors );
 	}
-	
+
 	/**
 	 * Returns a list containing those annotation mirrors from the input list,
 	 * which are of type <code>annotationType</code>. The input collection
 	 * remains untouched.
-	 * 
-	 * @param annotationMirrors
-	 *            A list of annotation mirrors.
-	 * @param annotationType
-	 *            The type to be compared against.
-	 * 
+	 *
+	 * @param annotationMirrors A list of annotation mirrors.
+	 * @param annotationType The type to be compared against.
+	 *
 	 * @return A list with those annotation mirrors from the input list, which
 	 *         are of type <code>annotationType</code>. May be empty but never
 	 *         null.
 	 */
 	public List<AnnotationMirror> filterByType(List<? extends AnnotationMirror> annotationMirrors, TypeMirror annotationType) {
 
-		List<AnnotationMirror> theValue = new ArrayList<AnnotationMirror>();
+		List<AnnotationMirror> theValue = CollectionHelper.newArrayList();
 
-		if(annotationMirrors == null || annotationType == null) {
+		if ( annotationMirrors == null || annotationType == null ) {
 			return theValue;
 		}
-		
-		for (AnnotationMirror oneAnnotationMirror : annotationMirrors) {
 
-			if (typeUtils.isSameType(oneAnnotationMirror.getAnnotationType(), annotationType)) {
-				theValue.add(oneAnnotationMirror);
+		for ( AnnotationMirror oneAnnotationMirror : annotationMirrors ) {
+
+			if ( typeUtils.isSameType( oneAnnotationMirror.getAnnotationType(), annotationType ) ) {
+				theValue.add( oneAnnotationMirror );
 			}
 		}
 
 		return theValue;
 	}
-	
-    public AnnotationMirror getMirror(List<? extends AnnotationMirror> annotationMirrors, Class<? extends Annotation> annotationClazz) {
-    	
-		if(annotationMirrors == null || annotationClazz == null) {
+
+	/**
+	 * Returns that mirror from the given list of annotation mirrors that
+	 * represents the annotation type specified by the given class.
+	 *
+	 * @param annotationMirrors A list of annotation mirrors.
+	 * @param annotationClazz The class of the annotation of interest.
+	 *
+	 * @return The mirror from the given list that represents the specified
+	 *         annotation or null, if the given list doesn't contain such a
+	 *         mirror.
+	 */
+	public AnnotationMirror getMirror(List<? extends AnnotationMirror> annotationMirrors, Class<? extends Annotation> annotationClazz) {
+
+		if ( annotationMirrors == null || annotationClazz == null ) {
 			return null;
 		}
-		
-		for (AnnotationMirror oneAnnotationMirror : annotationMirrors) {
 
-			TypeElement typeElement = elementUtils.getTypeElement(annotationClazz.getCanonicalName());
-						
-			if (typeUtils.isSameType(oneAnnotationMirror.getAnnotationType(), typeElement.asType())) {
+		TypeMirror mirrorForAnnotation = elementUtils.getTypeElement(
+				annotationClazz.getCanonicalName()
+		).asType();
+
+		for ( AnnotationMirror oneAnnotationMirror : annotationMirrors ) {
+
+			if ( typeUtils.isSameType(
+					oneAnnotationMirror.getAnnotationType(),
+					mirrorForAnnotation
+			) ) {
 				return oneAnnotationMirror;
 			}
 		}
 
-        return null;
-    }
+		return null;
+	}
 
+	/**
+	 * Returns a TypeMirror for the given class.
+	 *
+	 * @param clazz The class of interest. May not be a an array type.
+	 *
+	 * @return A TypeMirror for the given class.
+	 */
+	public TypeMirror getMirrorForType(Class<?> clazz) {
+
+		if ( clazz.isPrimitive() ) {
+			return primitiveMirrors.get( clazz );
+		}
+		else {
+
+			TypeElement typeElement = elementUtils.getTypeElement( clazz.getCanonicalName() );
+
+			if ( typeElement != null ) {
+				return typeUtils.getDeclaredType( typeElement );
+			}
+		}
+
+		throw new AssertionError( "Couldn't find a type element for class " + clazz );
+	}
+
+	/**
+	 * Returns the annotation value of the given annotation mirror with the
+	 * given name.
+	 *
+	 * @param annotationMirror An annotation mirror.
+	 * @param name The name of the annotation value of interest.
+	 *
+	 * @return The annotation value with the given name or null, if one of the
+	 *         input values is null or if no value with the given name exists
+	 *         within the given annotation mirror.
+	 */
+	public AnnotationValue getAnnotationValue(AnnotationMirror annotationMirror, String name) {
+
+		if ( annotationMirror == null || name == null ) {
+			return null;
+		}
+
+		Map<? extends ExecutableElement, ? extends AnnotationValue> elementValues = annotationMirror.getElementValues();
+
+		for ( Entry<? extends ExecutableElement, ? extends AnnotationValue> oneElementValue : elementValues.entrySet() ) {
+
+			if ( oneElementValue.getKey().getSimpleName().contentEquals( name ) ) {
+
+				return oneElementValue.getValue();
+			}
+		}
+
+		return null;
+	}
+
+	/**
+	 * Returns the given annotation mirror's array-typed annotation value with
+	 * the given name.
+	 *
+	 * @param annotationMirror An annotation mirror.
+	 * @param name The name of the annotation value of interest.
+	 *
+	 * @return The annotation value with the given name or an empty list, if no
+	 *         such value exists within the given annotation mirror or such a
+	 *         value exists but is not an array-typed one.
+	 */
+	public List<? extends AnnotationValue> getAnnotationArrayValue(AnnotationMirror annotationMirror, String name) {
+
+		AnnotationValue annotationValue = getAnnotationValue( annotationMirror, name );
+
+		if ( annotationValue == null ) {
+			return Collections.<AnnotationValue>emptyList();
+		}
+
+		List<? extends AnnotationValue> theValue = annotationValue.accept(
+				new SimpleAnnotationValueVisitor6<List<? extends AnnotationValue>, Void>() {
+
+					@Override
+					public List<? extends AnnotationValue> visitArray(List<? extends AnnotationValue> values, Void p) {
+						return values;
+					}
+
+				}, null
+		);
+
+		return theValue != null ? theValue : Collections
+				.<AnnotationValue>emptyList();
+	}
+
+	/**
+	 * <p>
+	 * Returns a set containing the "lowest" type per hierarchy contained in the
+	 * input set. The following examples shall demonstrate the behavior.
+	 * </p>
+	 * <ul>
+	 * <li>
+	 * Input: <code>String</code>; Output: <code>String</code></li>
+	 * <li>
+	 * Input: <code>Object</code>, <code>String</code>; Output:
+	 * <code>String</code></li>
+	 * <li>
+	 * Input: <code>Object</code>, <code>Collection</code>, <code>List</code>;
+	 * Output: <code>List</code></li>
+	 * <li>
+	 * Input: <code>Collection</code>, <code>Set</code>, <code>List</code>;
+	 * Output: <code>List</code>, <code>Set</code></li>
+	 * </ul>
+	 *
+	 * @param types A set of type mirrors.
+	 *
+	 * @return A set with the lowest types per hierarchy or null, if the input
+	 *         set was null.
+	 */
+	public Set<TypeMirror> keepLowestTypePerHierarchy(Set<TypeMirror> types) {
+
+		if ( types == null ) {
+			return null;
+		}
+
+		Set<TypeMirror> theValue = CollectionHelper.newHashSet();
+
+		for ( TypeMirror typeMirror1 : types ) {
+			boolean foundSubType = false;
+			for ( TypeMirror typeMirror2 : types ) {
+				if ( !typeUtils.isSameType( typeMirror2, typeMirror1 ) && typeUtils.isAssignable(
+						typeMirror2, typeMirror1
+				) ) {
+					foundSubType = true;
+					continue;
+				}
+			}
+			if ( !foundSubType ) {
+				theValue.add( typeMirror1 );
+			}
+		}
+
+		return theValue;
+	}
+
 }


Property changes on: validator/trunk/hibernate-validator-annotation-processor/src/main/java/org/hibernate/validator/ap/util/AnnotationApiHelper.java
___________________________________________________________________
Name: svn:keywords
   + Id

Modified: validator/trunk/hibernate-validator-annotation-processor/src/main/java/org/hibernate/validator/ap/util/ConstraintHelper.java
===================================================================
--- validator/trunk/hibernate-validator-annotation-processor/src/main/java/org/hibernate/validator/ap/util/ConstraintHelper.java	2010-02-25 19:04:40 UTC (rev 18896)
+++ validator/trunk/hibernate-validator-annotation-processor/src/main/java/org/hibernate/validator/ap/util/ConstraintHelper.java	2010-02-25 19:12:35 UTC (rev 18897)
@@ -1,4 +1,4 @@
-// $Id: ConstraintHelper.java 17946 2009-11-06 18:23:48Z hardy.ferentschik $
+// $Id$
 /*
 * JBoss, Home of Professional Open Source
 * Copyright 2009, Red Hat Middleware LLC, and individual contributors
@@ -25,18 +25,11 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.Map.Entry;
-
 import javax.lang.model.element.AnnotationMirror;
 import javax.lang.model.element.AnnotationValue;
 import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
 import javax.lang.model.element.Name;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
 import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.PrimitiveType;
-import javax.lang.model.type.TypeKind;
 import javax.lang.model.type.TypeMirror;
 import javax.lang.model.util.Elements;
 import javax.lang.model.util.SimpleAnnotationValueVisitor6;
@@ -64,11 +57,35 @@
  * whether a given annotation is allowed to be declared at a given element.
  *
  * @author Gunnar Morling
- *
  */
 public class ConstraintHelper {
 
 	/**
+	 * Possible results of a constraint check as returned by
+	 * {@link ConstraintHelper#checkConstraint(DeclaredType, TypeMirror)}.	 *
+	 *
+	 * @author Gunnar Morling
+	 */
+	public enum ConstraintCheckResult {
+
+		/**
+		 * The checked constraint is allowed at the evaluated type.
+		 */
+		ALLOWED,
+
+		/**
+		 * The checked constraint is not allowed at the evaluated type.
+		 */
+		DISALLOWED,
+
+		/**
+		 * Multiple validators were found, that could validate the checked
+		 * constrained at the evaluated type.
+		 */
+		MULTIPLE_VALIDATORS_FOUND
+	}
+
+	/**
 	 * The name of the package containing JSR 303 standard annotations
 	 * ("javax.validation.constraints").
 	 */
@@ -80,30 +97,62 @@
 
 	private Types typeUtils;
 
-	public ConstraintHelper(Elements elementUtils, Types typeUtils) {
+	private AnnotationApiHelper annotationApiHelper;
 
+	public ConstraintHelper(Elements elementUtils, Types typeUtils, AnnotationApiHelper annotationApiHelper) {
+
 		this.elementUtils = elementUtils;
 		this.typeUtils = typeUtils;
+		this.annotationApiHelper = annotationApiHelper;
 
-		CONSTRAINT_ANNOTATION_PACKAGE_NAME = elementUtils.getName(Size.class.getPackage().getName());
+		CONSTRAINT_ANNOTATION_PACKAGE_NAME = elementUtils.getName( Size.class.getPackage().getName() );
 
 		builtInConstraints = CollectionHelper.newHashMap();
 
-		registerAllowedTypesForBuiltInConstraint(AssertFalse.class, CollectionHelper.<Class<?>>asSet(Boolean.class));
-		registerAllowedTypesForBuiltInConstraint(AssertTrue.class, CollectionHelper.<Class<?>>asSet(Boolean.class));
-		registerAllowedTypesForBuiltInConstraint(DecimalMax.class, CollectionHelper.<Class<?>>asSet(Number.class, String.class));
-		registerAllowedTypesForBuiltInConstraint(DecimalMin.class, CollectionHelper.<Class<?>>asSet(Number.class, String.class));
-		registerAllowedTypesForBuiltInConstraint(Digits.class, CollectionHelper.<Class<?>>asSet(Number.class, String.class));
-		registerAllowedTypesForBuiltInConstraint(Future.class, CollectionHelper.<Class<?>>asSet(Calendar.class, Date.class));
-		registerAllowedTypesForBuiltInConstraint(Max.class, CollectionHelper.<Class<?>>asSet(Number.class, String.class));
-		registerAllowedTypesForBuiltInConstraint(Min.class, CollectionHelper.<Class<?>>asSet(Number.class, String.class));
-		registerAllowedTypesForBuiltInConstraint(NotNull.class, CollectionHelper.<Class<?>>asSet(Object.class));
-		registerAllowedTypesForBuiltInConstraint(Null.class, CollectionHelper.<Class<?>>asSet(Object.class));
-		registerAllowedTypesForBuiltInConstraint(Past.class, CollectionHelper.<Class<?>>asSet(Calendar.class, Date.class));
-		registerAllowedTypesForBuiltInConstraint(Pattern.class, CollectionHelper.<Class<?>>asSet(String.class));
-
-		//TODO GM: register all array types
-		registerAllowedTypesForBuiltInConstraint(Size.class, CollectionHelper.<Class<?>>asSet(Collection.class, Map.class, String.class, boolean[].class));
+		registerAllowedTypesForBuiltInConstraint(
+				AssertFalse.class, CollectionHelper.<Class<?>>asSet( Boolean.class )
+		);
+		registerAllowedTypesForBuiltInConstraint( AssertTrue.class, CollectionHelper.<Class<?>>asSet( Boolean.class ) );
+		registerAllowedTypesForBuiltInConstraint(
+				DecimalMax.class, CollectionHelper.<Class<?>>asSet( Number.class, String.class )
+		);
+		registerAllowedTypesForBuiltInConstraint(
+				DecimalMin.class, CollectionHelper.<Class<?>>asSet( Number.class, String.class )
+		);
+		registerAllowedTypesForBuiltInConstraint(
+				Digits.class, CollectionHelper.<Class<?>>asSet( Number.class, String.class )
+		);
+		registerAllowedTypesForBuiltInConstraint(
+				Future.class, CollectionHelper.<Class<?>>asSet( Calendar.class, Date.class )
+		);
+		registerAllowedTypesForBuiltInConstraint(
+				Max.class, CollectionHelper.<Class<?>>asSet( Number.class, String.class )
+		);
+		registerAllowedTypesForBuiltInConstraint(
+				Min.class, CollectionHelper.<Class<?>>asSet( Number.class, String.class )
+		);
+		registerAllowedTypesForBuiltInConstraint( NotNull.class, CollectionHelper.<Class<?>>asSet( Object.class ) );
+		registerAllowedTypesForBuiltInConstraint( Null.class, CollectionHelper.<Class<?>>asSet( Object.class ) );
+		registerAllowedTypesForBuiltInConstraint(
+				Past.class, CollectionHelper.<Class<?>>asSet( Calendar.class, Date.class )
+		);
+		registerAllowedTypesForBuiltInConstraint( Pattern.class, CollectionHelper.<Class<?>>asSet( String.class ) );
+		registerAllowedTypesForBuiltInConstraint(
+				Size.class, CollectionHelper.<Class<?>>asSet(
+						Object[].class,
+						boolean[].class,
+						byte[].class,
+						char[].class,
+						double[].class,
+						float[].class,
+						int[].class,
+						long[].class,
+						short[].class,
+						Collection.class,
+						Map.class,
+						String.class
+				)
+		);
 	}
 
 	/**
@@ -112,112 +161,157 @@
 	 * {@link Constraint} meta-annotation (which is only allowed at annotation
 	 * declarations).
 	 *
-	 * @param The
-	 *            element of interest.
+	 * @param element The element of interest.
+	 *
 	 * @return True, if the given element is a constraint annotation type, false
 	 *         otherwise.
 	 */
-	public boolean isConstraintAnnotation(TypeElement typeElement) {
-		return typeElement.getAnnotation(Constraint.class) != null;
+	public boolean isConstraintAnnotation(Element element) {
+		return element.getAnnotation( Constraint.class ) != null;
 	}
 
-	public boolean isAnnotationAllowedAtType(DeclaredType annotationType, TypeElement annotatedType) {
-
-		return isAnnotationAllowed(annotationType, annotatedType.asType());
+	/**
+	 * Checks, whether the given annotation mirror represents a constraint
+	 * annotation or not. That's the case, if the given mirror is annotated with
+	 * the {@link Constraint} meta-annotation (which is only allowed at
+	 * annotation declarations).
+	 *
+	 * @param annotationMirror The annotation mirror of interest.
+	 *
+	 * @return True, if the given mirror represents a constraint annotation
+	 *         type, false otherwise.
+	 */
+	public boolean isConstraintAnnotation(AnnotationMirror annotationMirror) {
+		return isConstraintAnnotation(
+				annotationMirror.getAnnotationType()
+						.asElement()
+		);
 	}
 
-	public boolean isAnnotationAllowedAtMethod(DeclaredType annotationType, ExecutableElement annotatedMethod) {
+	/**
+	 * Checks, whether the given annotation mirror represents a multi-valued
+	 * constraint such as {@link javax.validation.constraints.Pattern.List}.
+	 * That is the case if the annotation has an array-typed attribute with name
+	 * "value", that exclusively contains constraint annotations.
+	 *
+	 * @param annotationMirror The annotation mirror of interest.
+	 *
+	 * @return True, if the given mirror represents a multi-valued constraint,
+	 *         false otherwise.
+	 */
+	public boolean isMultiValuedConstraint(AnnotationMirror annotationMirror) {
 
-		return isAnnotationAllowed(annotationType, annotatedMethod.getReturnType());
-	}
+		List<? extends AnnotationValue> annotationArrayValue = annotationApiHelper.getAnnotationArrayValue(
+				annotationMirror, "value"
+		);
 
-	public boolean isAnnotationAllowedAtField(DeclaredType annotationType, VariableElement annotatedField) {
+		for ( AnnotationValue oneAnnotationValue : annotationArrayValue ) {
 
-		return isAnnotationAllowed(annotationType, annotatedField.asType());
-	}
+			Boolean isConstraintAnnotation = oneAnnotationValue.accept(
+					new SimpleAnnotationValueVisitor6<Boolean, Void>() {
 
-	// ==================================
-	// private API below
-	// ==================================
+						@Override
+						public Boolean visitAnnotation(
+								AnnotationMirror a, Void p) {
 
-	private Set<TypeMirror> getAllSuperTypes(TypeMirror type) {
+							return isConstraintAnnotation( a.getAnnotationType().asElement() );
+						}
+					}, null
+			);
 
-		Set<TypeMirror> allSuperTypes = CollectionHelper.newHashSet();
-
-		List<? extends TypeMirror> directSupertypes = typeUtils.directSupertypes(type);
-
-		while(!directSupertypes.isEmpty()) {
-
-			for (TypeMirror typeMirror : directSupertypes) {
-				allSuperTypes.add(typeMirror);
+			//TODO GM: have all parts of the array to be constraint annotations?
+			if ( Boolean.TRUE != isConstraintAnnotation ) {
+				return false;
 			}
-
-			List<TypeMirror> nextSuperTypes = CollectionHelper.newArrayList();
-
-			for (TypeMirror typeMirror : directSupertypes) {
-				nextSuperTypes.addAll(typeUtils.directSupertypes(typeMirror));
-			}
-			directSupertypes = nextSuperTypes;
 		}
 
-
-		return allSuperTypes;
+		return true;
 	}
 
 	/**
-	 * Checks whether the given annotation type may be specified at elements of
-	 * the specified type.
+	 * Returns a list with the constraint annotations contained in the given
+	 * array-valued annotation mirror.
+	 *
+	 * @param annotationMirror An array-valued annotation mirror (meaning it has an
+	 * array-typed attribute with name "value").
+	 *
+	 * @return A list with the constraint annotations part of the given
+	 *         multi-valued constraint annotation. Will return an empty list if
+	 *         the given annotation is no multi-valued annotation or if no
+	 *         constraint annotations are contained within the given
+	 *         array-valued annotation.
 	 */
-	private boolean isAnnotationAllowed(DeclaredType annotationType, TypeMirror typeOfAnnotatedElement) {
+	public List<AnnotationMirror> getPartsOfMultiValuedConstraint(
+			AnnotationMirror annotationMirror) {
 
-		//TODO GM: implement array type checking
-		if(typeOfAnnotatedElement.getKind() == TypeKind.ARRAY) {
-			return true;
-		}
+		final List<AnnotationMirror> theValue = CollectionHelper.newArrayList();
 
-		//convert primitive types into their corresponding boxed type
-		if(typeOfAnnotatedElement.getKind().isPrimitive()) {
-			typeOfAnnotatedElement = (DeclaredType)typeUtils.boxedClass((PrimitiveType)typeOfAnnotatedElement).asType();
-		}
+		for ( AnnotationValue oneValuePart : annotationApiHelper.getAnnotationArrayValue(
+				annotationMirror, "value"
+		) ) {
 
-		Set<TypeMirror> allowedTypesForConstraint = getAllowedTypesForConstraint(annotationType);
+			oneValuePart.accept(
+					new SimpleAnnotationValueVisitor6<Void, Void>() {
 
-		//is the annotation allowed at the given type?
-		for (TypeMirror oneAllowedType : allowedTypesForConstraint) {
-			if(typeUtils.isAssignable(typeOfAnnotatedElement, oneAllowedType)) {
-				return true;
-			}
+						@Override
+						public Void visitAnnotation(
+								AnnotationMirror a, Void p) {
+
+							if ( isConstraintAnnotation( a.getAnnotationType().asElement() ) ) {
+								theValue.add( a );
+							}
+
+							return null;
+						}
+
+					}, null
+			);
+
 		}
 
-		return false;
+		return theValue;
 	}
 
 	/**
-	 * Returns a set with all those type elements, at which the given constraint annotation
-	 * type may be specified.
+	 * Checks whether the given annotation type (which <b>must</b> be a
+	 * constraint annotation type) may be specified at elements of the specified
+	 * type.
 	 *
-	 * @param annotationType
-	 * @return
+	 * @param constraintAnnotationType A constraint annotation type.
+	 * @param typeOfAnnotatedElement A type which with an element is annotated.
+	 *
+	 * @return Whether the given constraint annotation may be specified at
+	 *         elements of the given type.
 	 */
-	private Set<TypeMirror> getAllowedTypesForConstraint(DeclaredType annotationType) {
+	public ConstraintCheckResult checkConstraint(DeclaredType constraintAnnotationType, TypeMirror typeOfAnnotatedElement) {
 
-		Set<TypeMirror> theValue;
+		return isBuiltInConstraint( constraintAnnotationType ) ?
+				checkBuiltInConstraint( constraintAnnotationType, typeOfAnnotatedElement ) :
+				checkCustomConstraint( constraintAnnotationType, typeOfAnnotatedElement );
+	}
 
-		if(isBuiltInConstraint(annotationType)) {
-			theValue = getAllowedTypesFromBuiltInConstraint(annotationType);
+	// ==================================
+	// private API below
+	// ==================================
+
+	private ConstraintCheckResult checkBuiltInConstraint(DeclaredType builtInAnnotationType, TypeMirror typeOfAnnotatedElement) {
+
+		Set<TypeMirror> allowedTypes = getAllowedTypesForBuiltInConstraint( builtInAnnotationType );
+
+		for ( TypeMirror oneAllowedType : allowedTypes ) {
+			if ( typeUtils.isAssignable( typeOfAnnotatedElement, oneAllowedType ) ) {
+				return ConstraintCheckResult.ALLOWED;
+			}
 		}
-		else {
-			theValue = getAllowedTypesFromCustomConstraint(annotationType);
-		}
 
-		return theValue;
+		return ConstraintCheckResult.DISALLOWED;
 	}
 
-	private Set<TypeMirror> getAllowedTypesFromBuiltInConstraint(DeclaredType builtInAnnotationType) {
+	private Set<TypeMirror> getAllowedTypesForBuiltInConstraint(DeclaredType builtInAnnotationType) {
 
-		Set<TypeMirror> theValue = builtInConstraints.get(builtInAnnotationType.asElement().getSimpleName());
+		Set<TypeMirror> theValue = builtInConstraints.get( builtInAnnotationType.asElement().getSimpleName() );
 
-		if(theValue == null) {
+		if ( theValue == null ) {
 			theValue = Collections.emptySet();
 		}
 
@@ -228,238 +322,224 @@
 	 * Returns a set containing all those types, at which the specified custom
 	 * constraint-annotation is allowed.
 	 *
-	 * @param customAnnotationType
-	 *            A custom constraint type.
+	 * @param customAnnotationType A custom constraint type.
+	 * @param typeOfAnnotatedElement
 	 *
 	 * @return A set with all types supported by the given constraint. May be
 	 *         empty in case of constraint composition, if there is no common
 	 *         type supported by all composing constraints.
 	 */
-	private Set<TypeMirror> getAllowedTypesFromCustomConstraint(DeclaredType customAnnotationType) {
+	private ConstraintCheckResult checkCustomConstraint(DeclaredType customAnnotationType, TypeMirror typeOfAnnotatedElement) {
 
-		Set<TypeMirror> theValue = null;
+		Set<AnnotationMirror> composingConstraints = getComposingConstraints( customAnnotationType );
+		boolean isComposedConstraint = !composingConstraints.isEmpty();
 
-		//the Constraint meta-annotation at the type declaration, e.g. "@Constraint(validatedBy = CheckCaseValidator.class)"
-		AnnotationMirror constraintMetaAnnotation = getConstraintMetaAnnotation(customAnnotationType);
+		for ( AnnotationMirror oneComposingConstraint : composingConstraints ) {
 
-		if(constraintMetaAnnotation == null) {
-			throw new IllegalArgumentException("Given type " + customAnnotationType + " isn't a constraint annotation type.");
-		}
+			ConstraintCheckResult annotationCheckResult = checkConstraint(
+					oneComposingConstraint.getAnnotationType(), typeOfAnnotatedElement
+			);
 
-		//the validator classes, e.g. [CheckCaseValidator.class]
-		List<? extends AnnotationValue> validatorClassReferences = getValidatorClassesFromConstraintMetaAnnotation(constraintMetaAnnotation);
-
-		for (AnnotationValue oneValidatorClassReference : validatorClassReferences) {
-
-			if(theValue == null) {
-				theValue = CollectionHelper.newHashSet();
+			if ( annotationCheckResult != ConstraintCheckResult.ALLOWED ) {
+				return annotationCheckResult;
 			}
 
-			theValue.add(getSupportedType(oneValidatorClassReference));
 		}
 
-		Set<AnnotationMirror> composingConstraints = getComposingConstraints(customAnnotationType);
+		Set<TypeMirror> theValue = getSupportedTypes(
+				customAnnotationType,
+				typeOfAnnotatedElement
+		);
 
-		for (AnnotationMirror oneComposingConstraint : composingConstraints) {
-
-			Set<TypeMirror> allowedTypesForComposingConstraint = getAllowedTypesForConstraint(oneComposingConstraint.getAnnotationType());
-
-			if(theValue == null) {
-				theValue = allowedTypesForComposingConstraint;
-			}
-			else {
-				theValue = intersect(theValue, allowedTypesForComposingConstraint);
-			}
+		if ( theValue.size() > 1 ) {
+			return ConstraintCheckResult.MULTIPLE_VALIDATORS_FOUND;
 		}
-
-		if(theValue == null) {
-			theValue = Collections.emptySet();
+		else if ( theValue.size() == 1 || isComposedConstraint ) {
+			return ConstraintCheckResult.ALLOWED;
 		}
-
-		return theValue;
+		else {
+			return ConstraintCheckResult.DISALLOWED;
+		}
 	}
 
-	private TypeMirror getSupportedType(AnnotationValue oneValidatorClassReference) {
+	/**
+	 * <p> Returns a set with those types supported by the constraint validators
+	 * specified in the @Constraint meta-annotation of the given constraint
+	 * annotation type to which the specified type can be assigned. </p>
+	 * <p>
+	 * If multiple types from the same inheritance hierarchy (e.g. Collection
+	 * and Set) are supported by the validators, only the "lowest" one (e.g.
+	 * Set) will be part of the result.
+	 * </p>
+	 *
+	 * @param constraintAnnotationType A constraint annotation type.
+	 * @param type A type.
+	 *
+	 * @return A set with the supported types.
+	 */
+	private Set<TypeMirror> getSupportedTypes(
+			DeclaredType constraintAnnotationType, TypeMirror type) {
 
-		TypeMirror validatorType = oneValidatorClassReference.accept(new SimpleAnnotationValueVisitor6<TypeMirror, Void>() {
+		Set<TypeMirror> theValue = CollectionHelper.newHashSet();
 
-			@Override
-			public TypeMirror visitType(TypeMirror t, Void p) {
-				return t;
-			}
-		}, null);
+		//the Constraint meta-annotation at the type declaration, e.g. "@Constraint(validatedBy = CheckCaseValidator.class)"
+		AnnotationMirror constraintMetaAnnotation = getConstraintMetaAnnotation( constraintAnnotationType );
 
-		//contains the bindings of the type parameters from the implemented ConstraintValidator
-		//interface, e.g. "ConstraintValidator<CheckCase, String>"
-		TypeMirror constraintValidatorImplementation = getConstraintValidatorSuperType(validatorType);
+		//the validator classes, e.g. [CheckCaseValidator.class]
+		List<? extends AnnotationValue> validatorClassReferences = getValidatorClassesFromConstraintMetaAnnotation(
+				constraintMetaAnnotation
+		);
 
+		for ( AnnotationValue oneValidatorClassReference : validatorClassReferences ) {
 
-		TypeMirror supportedType = constraintValidatorImplementation.accept(new TypeKindVisitor6<TypeMirror, Void>() {
+			TypeMirror supportedType = getSupportedType( oneValidatorClassReference );
 
-			@Override
-			public TypeMirror visitDeclared(DeclaredType constraintValidatorImplementation, Void p) {
-				//2nd type parameter contains the data type supported by current validator class, e.g. "String"
-				return constraintValidatorImplementation.getTypeArguments().get(1);
+			if ( typeUtils.isAssignable( type, supportedType ) ) {
+				theValue.add( supportedType );
 			}
+		}
 
-		}, null);
-
-		return supportedType;
+		return annotationApiHelper.keepLowestTypePerHierarchy( theValue );
 	}
 
-	private Set<TypeMirror> intersect(Set<TypeMirror> set1, Set<TypeMirror> set2) {
+	private TypeMirror getSupportedType(AnnotationValue oneValidatorClassReference) {
 
-		Set<TypeMirror> theValue = keepThoseWithSuperTypeAndNoSubType(set1, set2);
+		TypeMirror validatorType = oneValidatorClassReference.accept(
+				new SimpleAnnotationValueVisitor6<TypeMirror, Void>() {
 
-		theValue.addAll(keepThoseWithSuperTypeAndNoSubType(set2, set1));
+					@Override
+					public TypeMirror visitType(TypeMirror t, Void p) {
+						return t;
+					}
+				}, null
+		);
 
-		return theValue;
-	}
+		//contains the bindings of the type parameters from the implemented ConstraintValidator
+		//interface, e.g. "ConstraintValidator<CheckCase, String>"
+		TypeMirror constraintValidatorImplementation = getConstraintValidatorSuperType( validatorType );
 
-	//TODO GM: refactor
-	private Set<TypeMirror> keepThoseWithSuperTypeAndNoSubType(Set<TypeMirror> set1, Set<TypeMirror> set2) {
+		TypeMirror supportedType = constraintValidatorImplementation.accept(
+				new TypeKindVisitor6<TypeMirror, Void>() {
 
-		Set<TypeMirror> theValue = CollectionHelper.newHashSet();
-
-		for (TypeMirror oneType : set1) {
-
-			for (TypeMirror typeMirror : set2) {
-				if(typeUtils.isSameType(oneType, typeMirror)) {
-					theValue.add(oneType);
-					continue;
-				}
-			}
-
-			Set<TypeMirror> superTypes = getAllSuperTypes(oneType);
-			for (TypeMirror oneSuperType : superTypes) {
-				
-				for (TypeMirror typeMirror : set2) {
-					if(typeUtils.isSameType(oneSuperType, typeMirror)) {
-
-						if(!containsSubType(oneType, set2)) {
-							theValue.add(oneType);
-						}
+					@Override
+					public TypeMirror visitDeclared(DeclaredType constraintValidatorImplementation, Void p) {
+						//2nd type parameter contains the data type supported by current validator class, e.g. "String"
+						return constraintValidatorImplementation.getTypeArguments().get( 1 );
 					}
-				}
-			}
-		}
 
-		return theValue;
-	}
+				}, null
+		);
 
-	private boolean containsSubType(TypeMirror type, Set<TypeMirror> potentialSubTypes) {
-
-		for (TypeMirror onePotentialSubType : potentialSubTypes) {
-			
-			if(typeUtils.isAssignable(onePotentialSubType, type)) {
-				return true;
-			}
-		}
-
-		return false;
+		return supportedType;
 	}
 
 	private TypeMirror getConstraintValidatorSuperType(TypeMirror type) {
 
-		List<? extends TypeMirror> directSupertypes = typeUtils.directSupertypes(type);
+		List<? extends TypeMirror> directSupertypes = typeUtils.directSupertypes( type );
 
-		for (TypeMirror typeMirror : directSupertypes) {
-			if(typeUtils.asElement(typeMirror).getSimpleName().contentEquals(ConstraintValidator.class.getSimpleName())) {
+		for ( TypeMirror typeMirror : directSupertypes ) {
+			if ( typeUtils.asElement( typeMirror )
+					.getSimpleName()
+					.contentEquals( ConstraintValidator.class.getSimpleName() ) ) {
 				return typeMirror;
 			}
 		}
 
-		throw new AssertionError("Class " + type + " specified in @Constraint.validatedBy doesn't implement ConstraintValidator.");
+		throw new AssertionError( "Class " + type + " specified in @Constraint.validatedBy doesn't implement ConstraintValidator." );
 	}
 
 	/**
-	 * Retrieves the {@link Constraint} meta-annotation from the given constraint annotation.
+	 * Retrieves the {@link Constraint} meta-annotation from the given
+	 * constraint annotation.
 	 *
 	 * @param annotationType A constraint type.
 	 *
-	 * @return The Constraint meta-annotation or null if it isn't specified at the given type.
+	 * @return The Constraint meta-annotation.
+	 *
+	 * @throws IllegalArgumentException If the given constraint annotation type isn't annotated with
+	 *                                  the {@link Constraint} meta-annotation.
 	 */
 	private AnnotationMirror getConstraintMetaAnnotation(DeclaredType annotationType) {
 
 		List<? extends AnnotationMirror> annotationMirrors = annotationType.asElement().getAnnotationMirrors();
 
-		return new AnnotationApiHelper(elementUtils, typeUtils).getMirror(annotationMirrors, Constraint.class);
+		AnnotationMirror constraintMetaAnnotation = annotationApiHelper.getMirror(
+				annotationMirrors, Constraint.class
+		);
+
+		if ( constraintMetaAnnotation == null ) {
+			throw new IllegalArgumentException( "Given type " + annotationType + " isn't a constraint annotation type." );
+		}
+
+		return constraintMetaAnnotation;
 	}
 
 	private List<? extends AnnotationValue> getValidatorClassesFromConstraintMetaAnnotation(AnnotationMirror constraintMetaAnnotation) {
 
-		Map<? extends ExecutableElement, ? extends AnnotationValue> elementValues = constraintMetaAnnotation.getElementValues();
+		AnnotationValue validatedBy = annotationApiHelper.getAnnotationValue( constraintMetaAnnotation, "validatedBy" );
 
-		for (Entry<? extends ExecutableElement, ? extends AnnotationValue> oneElementValue : elementValues.entrySet()) {
+		return validatedBy.accept(
+				new SimpleAnnotationValueVisitor6<List<? extends AnnotationValue>, Void>() {
 
-			if(oneElementValue.getKey().getSimpleName().contentEquals("validatedBy")) {
+					@Override
+					public List<? extends AnnotationValue> visitArray(List<? extends AnnotationValue> values, Void p) {
+						return values;
+					}
 
-				//this is save, as we know that the "validatedBy" attribute is an array of classes
-				@SuppressWarnings("unchecked")
-				List<? extends AnnotationValue> validatorClasses = (List<? extends AnnotationValue>)oneElementValue.getValue().getValue();
-
-				return validatorClasses;
-			}
-		}
-
-		return Collections.emptyList();
+				}, null
+		);
 	}
 
 	private void registerAllowedTypesForBuiltInConstraint(Class<? extends Annotation> annotation, Set<Class<?>> allowedTypes) {
 
-		Set<TypeMirror> allowedTypesAsElements = CollectionHelper.newHashSet();
+		Set<TypeMirror> mirrorsForAllowedTypes = CollectionHelper.newHashSet();
 
-		for (Class<?> oneType : allowedTypes) {
-			if(oneType.isArray()) {
-					
-				//TODO GM: handle array types
+		for ( Class<?> oneAllowedType : allowedTypes ) {
+
+			if ( oneAllowedType.isArray() ) {
+				mirrorsForAllowedTypes.add( typeUtils.getArrayType( annotationApiHelper.getMirrorForType( oneAllowedType.getComponentType() ) ) );
 			}
 			else {
-				TypeElement typeElement = elementUtils.getTypeElement(oneType.getCanonicalName());
+				mirrorsForAllowedTypes.add( annotationApiHelper.getMirrorForType( oneAllowedType ) );
+			}
 
-				if(typeElement != null) {
-					allowedTypesAsElements.add(typeUtils.getDeclaredType(typeElement));
-				}
-			}
 		}
 
-		builtInConstraints.put(elementUtils.getName(annotation.getSimpleName()), allowedTypesAsElements);
+		builtInConstraints.put( elementUtils.getName( annotation.getSimpleName() ), mirrorsForAllowedTypes );
 	}
 
 	/**
-	 * Checks, whether the given type is a built-in constraint annotation (which
-	 * is the case, if is annotated with the {@link Constraint} meta-annotation
-	 * and is declared in the package <code>javax.validation.constraints</code>).
+	 * Checks, whether the given constraint annotation type is a built-in
+	 * constraint annotation (which is the case, if it is declared in the
+	 * package <code>javax.validation.constraints</code>).
 	 *
-	 * @param annotationType
-	 *            The type to check.
+	 * @param constraintAnnotationType The type to check.
+	 *
 	 * @return True, if the given type is a constraint annotation, false
 	 *         otherwise.
 	 */
-	private boolean isBuiltInConstraint(DeclaredType annotationType) {
+	private boolean isBuiltInConstraint(DeclaredType constraintAnnotationType) {
 
-		Element element = annotationType.asElement();
-
-		if(element.getAnnotation(Constraint.class) == null) {
-			return false;
-		}
-
-		return CONSTRAINT_ANNOTATION_PACKAGE_NAME.equals(elementUtils.getPackageOf(element).getQualifiedName());
+		return
+				CONSTRAINT_ANNOTATION_PACKAGE_NAME.equals(
+						elementUtils.getPackageOf( constraintAnnotationType.asElement() ).getQualifiedName()
+				);
 	}
 
 	private Set<AnnotationMirror> getComposingConstraints(DeclaredType constraintAnnotationType) {
 
 		Set<AnnotationMirror> theValue = CollectionHelper.newHashSet();
 
-		List<? extends AnnotationMirror> annotationMirrors = constraintAnnotationType.asElement().getAnnotationMirrors();
+		List<? extends AnnotationMirror> annotationMirrors = constraintAnnotationType.asElement()
+				.getAnnotationMirrors();
 
-		for (AnnotationMirror oneAnnotationMirror : annotationMirrors) {
-			if(getConstraintMetaAnnotation(oneAnnotationMirror.getAnnotationType()) != null) {
-				theValue.add(oneAnnotationMirror);
+		for ( AnnotationMirror oneAnnotationMirror : annotationMirrors ) {
+			if ( isConstraintAnnotation( oneAnnotationMirror.getAnnotationType().asElement() ) ) {
+				theValue.add( oneAnnotationMirror );
 			}
 		}
 
 		return theValue;
 	}
-	
+
 }
\ No newline at end of file


Property changes on: validator/trunk/hibernate-validator-annotation-processor/src/main/java/org/hibernate/validator/ap/util/ConstraintHelper.java
___________________________________________________________________
Name: svn:keywords
   + Id

Modified: validator/trunk/hibernate-validator-annotation-processor/src/main/resources/org/hibernate/validator/ap/ValidationProcessorMessages.properties
===================================================================
--- validator/trunk/hibernate-validator-annotation-processor/src/main/resources/org/hibernate/validator/ap/ValidationProcessorMessages.properties	2010-02-25 19:04:40 UTC (rev 18896)
+++ validator/trunk/hibernate-validator-annotation-processor/src/main/resources/org/hibernate/validator/ap/ValidationProcessorMessages.properties	2010-02-25 19:12:35 UTC (rev 18897)
@@ -6,4 +6,6 @@
 NOT_SUPPORTED_TYPE=The annotation @{0} is disallowed for this data type.
 NOT_SUPPORTED_RETURN_TYPE=The annotation @{0} is disallowed for the return type of this method.
 ONLY_CONSTRAINT_ANNOTATIONS_MAY_BE_ANNOTATED=Constraint annotations must not be specified at annotation types, which are no constraint annotation types themselves.
-STATIC_METHODS_MAY_NOT_BE_ANNOTATED=Only non-static methods may be annotated with constraint annotations. 
\ No newline at end of file
+STATIC_METHODS_MAY_NOT_BE_ANNOTATED=Only non-static methods may be annotated with constraint annotations.
+STATIC_FIELDS_MAY_NOT_BE_ANNOTATED=Only non-static fields may be annotated with constraint annotations.
+INVALID_DIAGNOSTIC_KIND_GIVEN=The given value {0} is no valid diagnostic kind. Kind.ERROR will be used.

Modified: validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/ConstraintValidationProcessorTest.java
===================================================================
--- validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/ConstraintValidationProcessorTest.java	2010-02-25 19:04:40 UTC (rev 18896)
+++ validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/ConstraintValidationProcessorTest.java	2010-02-25 19:12:35 UTC (rev 18897)
@@ -1,4 +1,4 @@
-// $Id: ConstraintValidationProcessorTest.java 17946 2009-11-06 18:23:48Z hardy.ferentschik $
+// $Id$
 /*
 * JBoss, Home of Professional Open Source
 * Copyright 2009, Red Hat Middleware LLC, and individual contributors
@@ -24,10 +24,12 @@
 import javax.tools.ToolProvider;
 
 import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import org.hibernate.validator.ap.testmodel.FieldLevelValidationUsingBuiltInConstraints;
 import org.hibernate.validator.ap.testmodel.MethodLevelValidationUsingBuiltInConstraints;
+import org.hibernate.validator.ap.testmodel.MultipleConstraintsOfSameType;
 import org.hibernate.validator.ap.testmodel.boxing.ValidLong;
 import org.hibernate.validator.ap.testmodel.boxing.ValidLongValidator;
 import org.hibernate.validator.ap.testmodel.boxing.ValidationUsingBoxing;
@@ -51,12 +53,19 @@
 import org.hibernate.validator.ap.testmodel.customconstraints.CheckCaseValidator;
 import org.hibernate.validator.ap.testmodel.customconstraints.FieldLevelValidationUsingCustomConstraints;
 import org.hibernate.validator.ap.testmodel.invalidcomposedconstraint.ValidCustomerNumber;
+import org.hibernate.validator.ap.testmodel.nouniquevalidatorresolution.NoUniqueValidatorResolution;
+import org.hibernate.validator.ap.testmodel.nouniquevalidatorresolution.SerializableCollection;
+import org.hibernate.validator.ap.testmodel.nouniquevalidatorresolution.Size;
+import org.hibernate.validator.ap.testmodel.nouniquevalidatorresolution.SizeValidatorForCollection;
+import org.hibernate.validator.ap.testmodel.nouniquevalidatorresolution.SizeValidatorForSerializable;
+import org.hibernate.validator.ap.testmodel.nouniquevalidatorresolution.SizeValidatorForSet;
 import org.hibernate.validator.ap.testutil.CompilerTestHelper;
 import org.hibernate.validator.ap.util.DiagnosticExpection;
 
-import static org.hibernate.validator.ap.testutil.CompilerTestHelper.assertDiagnostics;
+import static org.hibernate.validator.ap.testutil.CompilerTestHelper.assertThatDiagnosticsMatch;
 import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
 
 /**
  * Test for {@link ConstraintValidationProcessor} using the Java compiler
@@ -65,8 +74,11 @@
  * @author Gunnar Morling.
  */
 public class ConstraintValidationProcessorTest {
+
 	private static CompilerTestHelper compilerHelper;
 
+	private DiagnosticCollector<JavaFileObject> diagnostics;
+
 	@BeforeClass
 	public static void setUpCompilerHelper() {
 
@@ -88,25 +100,42 @@
 				);
 	}
 
+	@BeforeMethod
+	public void setUp() {
+		diagnostics = new DiagnosticCollector<JavaFileObject>();
+	}
+
 	@Test
 	public void fieldLevelValidationUsingBuiltInConstraints() {
 
-		DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
-
 		File sourceFile = compilerHelper.getSourceFile( FieldLevelValidationUsingBuiltInConstraints.class );
 
 		boolean compilationResult =
 				compilerHelper.compile( new ConstraintValidationProcessor(), diagnostics, sourceFile );
 
 		assertFalse( compilationResult );
-		assertDiagnostics( diagnostics, new DiagnosticExpection( Kind.ERROR, 43 ) );
+		assertThatDiagnosticsMatch(
+				diagnostics, new DiagnosticExpection( Kind.ERROR, 54 ), new DiagnosticExpection( Kind.ERROR, 60 )
+		);
 	}
 
 	@Test
+	public void compilationSucceedsDueToDiagnosticKindWarning() {
+
+		File sourceFile = compilerHelper.getSourceFile( FieldLevelValidationUsingBuiltInConstraints.class );
+
+		boolean compilationResult =
+				compilerHelper.compile( new ConstraintValidationProcessor(), diagnostics, Kind.WARNING, sourceFile );
+
+		assertTrue( compilationResult );
+		assertThatDiagnosticsMatch(
+				diagnostics, new DiagnosticExpection( Kind.WARNING, 54 ), new DiagnosticExpection( Kind.WARNING, 60 )
+		);
+	}
+
+	@Test
 	public void fieldLevelValidationUsingCustomConstraints() {
 
-		DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
-
 		File sourceFile1 = compilerHelper.getSourceFile( FieldLevelValidationUsingCustomConstraints.class );
 		File sourceFile2 = compilerHelper.getSourceFile( CheckCase.class );
 		File sourceFile3 = compilerHelper.getSourceFile( CaseMode.class );
@@ -123,21 +152,19 @@
 				);
 
 		assertFalse( compilationResult );
-		assertDiagnostics( diagnostics, new DiagnosticExpection( Kind.ERROR, 30 ) );
+		assertThatDiagnosticsMatch( diagnostics, new DiagnosticExpection( Kind.ERROR, 30 ) );
 	}
 
 	@Test
 	public void methodLevelValidationUsingBuiltInConstraints() {
 
-		DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
-
 		File sourceFile = compilerHelper.getSourceFile( MethodLevelValidationUsingBuiltInConstraints.class );
 
 		boolean compilationResult =
 				compilerHelper.compile( new ConstraintValidationProcessor(), diagnostics, sourceFile );
 
 		assertFalse( compilationResult );
-		assertDiagnostics(
+		assertThatDiagnosticsMatch(
 				diagnostics,
 				new DiagnosticExpection( Kind.ERROR, 32 ),
 				new DiagnosticExpection( Kind.ERROR, 39 ),
@@ -149,8 +176,6 @@
 	@Test
 	public void classLevelValidation() {
 
-		DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
-
 		File sourceFile1 = compilerHelper.getSourceFile( ClassLevelValidation.class );
 		File sourceFile2 = compilerHelper.getSourceFile( ValidCustomer.class );
 		File sourceFile3 = compilerHelper.getSourceFile( ValidCustomerValidator.class );
@@ -161,14 +186,12 @@
 				);
 
 		assertFalse( compilationResult );
-		assertDiagnostics( diagnostics, new DiagnosticExpection( Kind.ERROR, 28 ) );
+		assertThatDiagnosticsMatch( diagnostics, new DiagnosticExpection( Kind.ERROR, 28 ) );
 	}
 
 	@Test
 	public void validationUsingComposedConstraint() {
 
-		DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
-
 		File sourceFile1 = compilerHelper.getSourceFile( FieldLevelValidationUsingComposedConstraint.class );
 		File sourceFile2 = compilerHelper.getSourceFile( ValidOrderNumber.class );
 
@@ -176,14 +199,12 @@
 				compilerHelper.compile( new ConstraintValidationProcessor(), diagnostics, sourceFile1, sourceFile2 );
 
 		assertFalse( compilationResult );
-		assertDiagnostics( diagnostics, new DiagnosticExpection( Kind.ERROR, 29 ) );
+		assertThatDiagnosticsMatch( diagnostics, new DiagnosticExpection( Kind.ERROR, 29 ) );
 	}
 
 	@Test
 	public void validationUsingComplexComposedConstraint() {
 
-		DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
-
 		File sourceFile1 = compilerHelper.getSourceFile( FieldLevelValidationUsingComplexComposedConstraint.class );
 		File sourceFile2 = compilerHelper.getSourceFile( ComposedConstraint.class );
 		File sourceFile3 = compilerHelper.getSourceFile( ComposingConstraint1.class );
@@ -212,10 +233,9 @@
 				);
 
 		assertFalse( compilationResult );
-		assertDiagnostics(
+		assertThatDiagnosticsMatch(
 				diagnostics,
 				new DiagnosticExpection( Kind.ERROR, 29 ),
-				new DiagnosticExpection( Kind.ERROR, 32 ),
 				new DiagnosticExpection( Kind.ERROR, 41 ),
 				new DiagnosticExpection( Kind.ERROR, 50 ),
 				new DiagnosticExpection( Kind.ERROR, 56 )
@@ -225,8 +245,6 @@
 	@Test
 	public void validationUsingBoxing() {
 
-		DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
-
 		File sourceFile1 = compilerHelper.getSourceFile( ValidationUsingBoxing.class );
 		File sourceFile2 = compilerHelper.getSourceFile( ValidLong.class );
 		File sourceFile3 = compilerHelper.getSourceFile( ValidLongValidator.class );
@@ -237,7 +255,7 @@
 				);
 
 		assertFalse( compilationResult );
-		assertDiagnostics(
+		assertThatDiagnosticsMatch(
 				diagnostics,
 				new DiagnosticExpection( Kind.ERROR, 31 ),
 				new DiagnosticExpection( Kind.ERROR, 37 ),
@@ -248,18 +266,66 @@
 	}
 
 	@Test
-	public void constraintAnnotationGivenAtNonConstraintAnnotationType() {
+	public void testThatSpecifyingConstraintAnnotationAtNonConstraintAnnotationTypeCausesCompilationError() {
 
-		DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
-
 		File sourceFile = compilerHelper.getSourceFile( ValidCustomerNumber.class );
 
 		boolean compilationResult =
 				compilerHelper.compile( new ConstraintValidationProcessor(), diagnostics, sourceFile );
 
 		assertFalse( compilationResult );
-		assertDiagnostics(
+		assertThatDiagnosticsMatch(
 				diagnostics, new DiagnosticExpection( Kind.ERROR, 28 ), new DiagnosticExpection( Kind.ERROR, 29 )
 		);
 	}
-}
\ No newline at end of file
+
+	@Test
+	public void testThatNonUniqueValidatorResolutionCausesCompilationError() {
+
+		File sourceFile1 = compilerHelper.getSourceFile( NoUniqueValidatorResolution.class );
+		File sourceFile2 = compilerHelper.getSourceFile( Size.class );
+		File sourceFile3 = compilerHelper.getSourceFile( SizeValidatorForCollection.class );
+		File sourceFile4 = compilerHelper.getSourceFile( SizeValidatorForSerializable.class );
+		File sourceFile5 = compilerHelper.getSourceFile( SerializableCollection.class );
+		File sourceFile6 = compilerHelper.getSourceFile( SizeValidatorForSet.class );
+
+		boolean compilationResult =
+				compilerHelper.compile(
+						new ConstraintValidationProcessor(),
+						diagnostics,
+						sourceFile1,
+						sourceFile2,
+						sourceFile3,
+						sourceFile4,
+						sourceFile5,
+						sourceFile6
+				);
+
+		assertFalse( compilationResult );
+		assertThatDiagnosticsMatch(
+				diagnostics, new DiagnosticExpection(
+						Kind.ERROR, 33
+				)
+		);
+	}
+
+	@Test
+	public void testThatMultiValuedConstrainedIsOnlyGivenAtSupportedType() {
+
+		File sourceFile1 = compilerHelper.getSourceFile( MultipleConstraintsOfSameType.class );
+
+		boolean compilationResult =
+				compilerHelper.compile(
+						new ConstraintValidationProcessor(),
+						diagnostics,
+						sourceFile1
+				);
+
+		assertFalse( compilationResult );
+		assertThatDiagnosticsMatch(
+				diagnostics, new DiagnosticExpection(
+						Kind.ERROR, 33
+				), new DiagnosticExpection( Kind.ERROR, 33 )
+		);
+	}
+}


Property changes on: validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/ConstraintValidationProcessorTest.java
___________________________________________________________________
Name: svn:keywords
   + Id

Modified: validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/FieldLevelValidationUsingBuiltInConstraints.java
===================================================================
--- validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/FieldLevelValidationUsingBuiltInConstraints.java	2010-02-25 19:04:40 UTC (rev 18896)
+++ validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/FieldLevelValidationUsingBuiltInConstraints.java	2010-02-25 19:12:35 UTC (rev 18897)
@@ -1,4 +1,4 @@
-// $Id: FieldLevelValidationUsingBuiltInConstraints.java 17946 2009-11-06 18:23:48Z hardy.ferentschik $
+// $Id$
 /*
 * JBoss, Home of Professional Open Source
 * Copyright 2009, Red Hat Middleware LLC, and individual contributors
@@ -23,26 +23,49 @@
 import javax.validation.constraints.Size;
 
 public class FieldLevelValidationUsingBuiltInConstraints {
+
 	@Size(min = 10)
 	public String string;
 
 	@Size(min = 10)
-	public Collection<String> collection;
+	public Collection collection1;
 
-	//TODO GM: support array-typed elements
+	@Size(min = 10)
+	public Collection<?> collection2;
 
+	@Size(min = 10)
+	public Collection<String> stringCollection;
+
 	/**
 	 * Allowed, as List extends Collection.
 	 */
 	@Size(min = 10)
-	public List<String> list;
+	public List list1;
 
+	@Size(min = 10)
+	public List<?> list2;
+
+	@Size(min = 10)
+	public List<String> stringList;
+
 	/**
-	 * Not allowed.
+	 * Not allowed (unsupported type).
 	 */
 	@Size(min = 10)
 	public Date date;
 
+	/**
+	 * Not allowed (static field).
+	 */
 	@Size(min = 10)
 	public static String staticString;
+
+	@Size(min = 10)
+	public Object[] objectArray;
+
+	@Size(min = 10)
+	public Integer[] integerArray;
+
+	@Size(min = 10)
+	public int[] intArray;
 }


Property changes on: validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/FieldLevelValidationUsingBuiltInConstraints.java
___________________________________________________________________
Name: svn:keywords
   + Id

Added: validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/MultipleConstraintsOfSameType.java
===================================================================
--- validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/MultipleConstraintsOfSameType.java	                        (rev 0)
+++ validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/MultipleConstraintsOfSameType.java	2010-02-25 19:12:35 UTC (rev 18897)
@@ -0,0 +1,35 @@
+// $Id$
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2009, Red Hat Middleware LLC, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* 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
+* 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.hibernate.validator.ap.testmodel;
+
+import java.util.Date;
+
+import javax.validation.constraints.Pattern;
+import javax.validation.constraints.Pattern.List;
+
+public class MultipleConstraintsOfSameType {
+	
+	@List(value = { @Pattern(regexp = ""), @Pattern(regexp = "") })
+	public String string;
+
+	/**
+	 * Not allowed.
+	 */
+	@List(value = { @Pattern(regexp = ""), @Pattern(regexp = "") })
+	public Date date;
+}


Property changes on: validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/MultipleConstraintsOfSameType.java
___________________________________________________________________
Name: svn:keywords
   + Id

Modified: validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/invalidcomposedconstraint/ValidCustomerNumber.java
===================================================================
--- validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/invalidcomposedconstraint/ValidCustomerNumber.java	2010-02-25 19:04:40 UTC (rev 18896)
+++ validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/invalidcomposedconstraint/ValidCustomerNumber.java	2010-02-25 19:12:35 UTC (rev 18897)
@@ -1,4 +1,4 @@
-// $Id: ValidCustomerNumber.java 17946 2009-11-06 18:23:48Z hardy.ferentschik $
+// $Id$
 /*
 * JBoss, Home of Professional Open Source
 * Copyright 2009, Red Hat Middleware LLC, and individual contributors
@@ -22,8 +22,8 @@
 import javax.validation.constraints.Size;
 
 /**
- * Constraint annotations are not allowed here, as ValidOrderNumber
- * isn't a proper constraint type definition.
+ * Constraint annotations are not allowed here, as ValidCustomerNumber isn't a
+ * proper constraint type definition.
  */
 @NotNull
 @Size(min = 10, max = 10)


Property changes on: validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/invalidcomposedconstraint/ValidCustomerNumber.java
___________________________________________________________________
Name: svn:keywords
   + Id

Added: validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/nouniquevalidatorresolution/NoUniqueValidatorResolution.java
===================================================================
--- validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/nouniquevalidatorresolution/NoUniqueValidatorResolution.java	                        (rev 0)
+++ validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/nouniquevalidatorresolution/NoUniqueValidatorResolution.java	2010-02-25 19:12:35 UTC (rev 18897)
@@ -0,0 +1,35 @@
+// $Id$
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2009, Red Hat Middleware LLC, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* 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
+* 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.hibernate.validator.ap.testmodel.nouniquevalidatorresolution;
+
+import java.util.Set;
+
+public class NoUniqueValidatorResolution {
+
+	/**
+	 * Allowed, as there is one maximally specific validator.
+	 */
+	@Size
+	public Set<?> set;
+
+	/**
+	 * Not allowed, as two maximally specific validators exist.
+	 */
+	@Size
+	public SerializableCollection<?> serializableCollection;
+}


Property changes on: validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/nouniquevalidatorresolution/NoUniqueValidatorResolution.java
___________________________________________________________________
Name: svn:keywords
   + Id

Added: validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/nouniquevalidatorresolution/SerializableCollection.java
===================================================================
--- validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/nouniquevalidatorresolution/SerializableCollection.java	                        (rev 0)
+++ validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/nouniquevalidatorresolution/SerializableCollection.java	2010-02-25 19:12:35 UTC (rev 18897)
@@ -0,0 +1,25 @@
+// $Id$
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * 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
+ * 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.hibernate.validator.ap.testmodel.nouniquevalidatorresolution;
+
+import java.io.Serializable;
+import java.util.Collection;
+
+public interface SerializableCollection<T> extends Serializable, Collection<T> {
+
+}


Property changes on: validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/nouniquevalidatorresolution/SerializableCollection.java
___________________________________________________________________
Name: svn:keywords
   + Id

Added: validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/nouniquevalidatorresolution/Size.java
===================================================================
--- validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/nouniquevalidatorresolution/Size.java	                        (rev 0)
+++ validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/nouniquevalidatorresolution/Size.java	2010-02-25 19:12:35 UTC (rev 18897)
@@ -0,0 +1,43 @@
+// $Id$
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2009, Red Hat Middleware LLC, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* 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
+* 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.hibernate.validator.ap.testmodel.nouniquevalidatorresolution;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import javax.validation.Constraint;
+import javax.validation.Payload;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+ at Target({ METHOD, FIELD, ANNOTATION_TYPE })
+ at Retention(RUNTIME)
+ at Constraint(validatedBy = {
+		SizeValidatorForCollection.class, SizeValidatorForSerializable.class, SizeValidatorForSet.class
+})
+ at Documented
+public @interface Size {
+	String message() default "";
+
+	Class<?>[] groups() default { };
+
+	Class<? extends Payload>[] payload() default { };
+}


Property changes on: validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/nouniquevalidatorresolution/Size.java
___________________________________________________________________
Name: svn:keywords
   + Id

Added: validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/nouniquevalidatorresolution/SizeValidatorForCollection.java
===================================================================
--- validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/nouniquevalidatorresolution/SizeValidatorForCollection.java	                        (rev 0)
+++ validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/nouniquevalidatorresolution/SizeValidatorForCollection.java	2010-02-25 19:12:35 UTC (rev 18897)
@@ -0,0 +1,32 @@
+// $Id$
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2009, Red Hat Middleware LLC, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* 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
+* 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.hibernate.validator.ap.testmodel.nouniquevalidatorresolution;
+
+import java.util.Collection;
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+public class SizeValidatorForCollection implements ConstraintValidator<Size, Collection> {
+
+	public void initialize(Size constraintAnnotation) {
+	}
+
+	public boolean isValid(Collection object, ConstraintValidatorContext constraintContext) {
+		return true;
+	}
+}


Property changes on: validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/nouniquevalidatorresolution/SizeValidatorForCollection.java
___________________________________________________________________
Name: svn:keywords
   + Id

Added: validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/nouniquevalidatorresolution/SizeValidatorForSerializable.java
===================================================================
--- validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/nouniquevalidatorresolution/SizeValidatorForSerializable.java	                        (rev 0)
+++ validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/nouniquevalidatorresolution/SizeValidatorForSerializable.java	2010-02-25 19:12:35 UTC (rev 18897)
@@ -0,0 +1,32 @@
+// $Id$
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2009, Red Hat Middleware LLC, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* 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
+* 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.hibernate.validator.ap.testmodel.nouniquevalidatorresolution;
+
+import java.io.Serializable;
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+public class SizeValidatorForSerializable implements ConstraintValidator<Size, Serializable> {
+
+	public void initialize(Size constraintAnnotation) {
+	}
+
+	public boolean isValid(Serializable object, ConstraintValidatorContext constraintContext) {
+		return true;
+	}
+}


Property changes on: validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/nouniquevalidatorresolution/SizeValidatorForSerializable.java
___________________________________________________________________
Name: svn:keywords
   + Id

Added: validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/nouniquevalidatorresolution/SizeValidatorForSet.java
===================================================================
--- validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/nouniquevalidatorresolution/SizeValidatorForSet.java	                        (rev 0)
+++ validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/nouniquevalidatorresolution/SizeValidatorForSet.java	2010-02-25 19:12:35 UTC (rev 18897)
@@ -0,0 +1,32 @@
+// $Id$
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2009, Red Hat Middleware LLC, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* 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
+* 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.hibernate.validator.ap.testmodel.nouniquevalidatorresolution;
+
+import java.util.Set;
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+public class SizeValidatorForSet implements ConstraintValidator<Size, Set> {
+
+	public void initialize(Size constraintAnnotation) {
+	}
+
+	public boolean isValid(Set object, ConstraintValidatorContext constraintContext) {
+		return true;
+	}
+}


Property changes on: validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/nouniquevalidatorresolution/SizeValidatorForSet.java
___________________________________________________________________
Name: svn:keywords
   + Id

Modified: validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testutil/CompilerTestHelper.java
===================================================================
--- validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testutil/CompilerTestHelper.java	2010-02-25 19:04:40 UTC (rev 18896)
+++ validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testutil/CompilerTestHelper.java	2010-02-25 19:12:35 UTC (rev 18897)
@@ -1,4 +1,4 @@
-// $Id: CompilerTestHelper.java 17946 2009-11-06 18:23:48Z hardy.ferentschik $
+// $Id$
 /*
 * JBoss, Home of Professional Open Source
 * Copyright 2009, Red Hat Middleware LLC, and individual contributors
@@ -23,6 +23,7 @@
 import java.util.List;
 import javax.annotation.processing.Processor;
 import javax.tools.Diagnostic;
+import javax.tools.Diagnostic.Kind;
 import javax.tools.DiagnosticCollector;
 import javax.tools.JavaCompiler;
 import javax.tools.JavaCompiler.CompilationTask;
@@ -40,6 +41,7 @@
  * @author Gunnar Morling
  */
 public class CompilerTestHelper {
+
 	private final JavaCompiler compiler;
 
 	private final String sourceBaseDir;
@@ -57,6 +59,13 @@
 		this.pathToBeanValidationApiJar = pathToBeanValidationApiJar;
 	}
 
+	/**
+	 * Retrieves a file object containing the source of the given class.
+	 *
+	 * @param clazz The class of interest.
+	 *
+	 * @return A file with the source of the given class.
+	 */
 	public File getSourceFile(Class<?> clazz) {
 
 		String sourceFileName =
@@ -65,16 +74,49 @@
 		return new File( sourceBaseDir + sourceFileName );
 	}
 
+	/**
+	 * Creates and executes a {@link CompilationTask} using the given input.
+	 *
+	 * @param annotationProcessor An annotation processor to be attached to the task.
+	 * @param diagnostics An diagnostics listener to be attached to the task.
+	 * @param sourceFiles The source files to be compiled.
+	 *
+	 * @return True, if the source files could be compiled successfully (meaning
+	 *         in especially, that the given annotation processor didn't raise
+	 *         any errors), false otherwise.
+	 */
 	public boolean compile(
 			Processor annotationProcessor, DiagnosticCollector<JavaFileObject> diagnostics, File... sourceFiles) {
 
+		return compile( annotationProcessor, diagnostics, Kind.ERROR, sourceFiles );
+	}
+
+	/**
+	 * Creates and executes a {@link CompilationTask} using the given input.
+	 *
+	 * @param annotationProcessor An annotation processor to be attached to the task.
+	 * @param diagnostics An diagnostics listener to be attached to the task.
+	 * @param diagnosticKind A value for the "diagnosticKind" option.
+	 * @param sourceFiles The source files to be compiled.
+	 *
+	 * @return True, if the source files could be compiled successfully (meaning
+	 *         in especially, that the given annotation processor didn't raise
+	 *         any errors), false otherwise.
+	 */
+	public boolean compile(
+			Processor annotationProcessor, DiagnosticCollector<JavaFileObject> diagnostics, Kind diagnosticKind, File... sourceFiles) {
+
 		StandardJavaFileManager fileManager =
 				compiler.getStandardFileManager( null, null, null );
 
 		Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjects( sourceFiles );
 
 		List<String> optionList = new ArrayList<String>();
-		optionList.addAll( Arrays.asList( "-classpath", pathToBeanValidationApiJar ) );
+		optionList.addAll(
+				Arrays.asList(
+						"-classpath", pathToBeanValidationApiJar, "-AdiagnosticKind=" + diagnosticKind, "-d", "target"
+				)
+		);
 
 		CompilationTask task = compiler.getTask( null, fileManager, diagnostics, optionList, null, compilationUnits );
 		task.setProcessors( Arrays.asList( annotationProcessor ) );
@@ -82,7 +124,21 @@
 		return task.call();
 	}
 
-	public static void assertDiagnostics(DiagnosticCollector<JavaFileObject> diagnostics, DiagnosticExpection... expections) {
+	/**
+	 * <p>
+	 * Asserts, that the given diagnostics match with the given expectations.
+	 * </p>
+	 * <p>
+	 * First checks, whether the number of actual diagnostics matches with the
+	 * number of given expectations. If that's the case, {@link Kind} and line
+	 * number of each expectation are compared.
+	 * </p>
+	 *
+	 * @param diagnostics The actual diagnostics as populated by the executed
+	 * {@link CompilationTask}.
+	 * @param expections The expectations to compare against.
+	 */
+	public static void assertThatDiagnosticsMatch(DiagnosticCollector<JavaFileObject> diagnostics, DiagnosticExpection... expections) {
 
 		List<Diagnostic<? extends JavaFileObject>> diagnosticsList = diagnostics.getDiagnostics();
 
@@ -95,7 +151,7 @@
 				System.out.println( diagnosticsList );
 			}
 
-			assertEquals( diagnosticsList.size(), expections.length, "Wrong number of diagnostic expections." );
+			assertEquals( diagnosticsList.size(), expections.length, "Wrong number of diagnostics." );
 
 			int i = 0;
 			for ( DiagnosticExpection oneExpection : expections ) {


Property changes on: validator/trunk/hibernate-validator-annotation-processor/src/test/java/org/hibernate/validator/ap/testutil/CompilerTestHelper.java
___________________________________________________________________
Name: svn:keywords
   + Id



More information about the hibernate-commits mailing list