Skip to content

Commit

Permalink
HV-270 Add verification for annotation parameters and corresponding t…
Browse files Browse the repository at this point in the history
…ests:

@DecimalMax, @DecimalMin should have a valid BigDecimal representation
@digits should have integer >= 0 and fraction >= 0
@Length should have min >= 0, max >= 0 and min <= max
@pattern should have a valid regular expression
@SiZe should have min >=0, max >= 0 and min <= max
@ScriptAssert should have script, lang and alias with a length > 0
  • Loading branch information
marko-bekhta authored and gsmet committed Nov 29, 2016
1 parent 6282ad4 commit 1b4b28f
Show file tree
Hide file tree
Showing 22 changed files with 1,064 additions and 14 deletions.
Expand Up @@ -11,6 +11,11 @@
import javax.lang.model.element.Element;
import javax.lang.model.util.Types;

import org.hibernate.validator.ap.checks.annotationparameters.AnnotationParametersDecimalMinMaxCheck;
import org.hibernate.validator.ap.checks.annotationparameters.AnnotationParametersDigitsCheck;
import org.hibernate.validator.ap.checks.annotationparameters.AnnotationParametersPatternCheck;
import org.hibernate.validator.ap.checks.annotationparameters.AnnotationParametersScriptAssertCheck;
import org.hibernate.validator.ap.checks.annotationparameters.AnnotationParametersSizeLengthCheck;
import org.hibernate.validator.ap.util.AnnotationApiHelper;
import org.hibernate.validator.ap.util.CollectionHelper;
import org.hibernate.validator.ap.util.ConstraintHelper;
Expand Down Expand Up @@ -49,17 +54,33 @@ public class ConstraintCheckFactory {
private static final SingleValuedChecks NULL_CHECKS = new SingleValuedChecks();

public ConstraintCheckFactory(Types typeUtils, ConstraintHelper constraintHelper, AnnotationApiHelper annotationApiHelper, boolean methodConstraintsSupported) {

this.constraintHelper = constraintHelper;

fieldChecks = CollectionHelper.newHashMap();
fieldChecks.put(
AnnotationType.CONSTRAINT_ANNOTATION,
new SingleValuedChecks( new StaticCheck(), new TypeCheck( constraintHelper ) )
new SingleValuedChecks(
new StaticCheck(),
new TypeCheck( constraintHelper ),
new AnnotationParametersSizeLengthCheck( annotationApiHelper ),
new AnnotationParametersPatternCheck( annotationApiHelper ),
new AnnotationParametersScriptAssertCheck( annotationApiHelper ),
new AnnotationParametersDigitsCheck( annotationApiHelper ),
new AnnotationParametersDecimalMinMaxCheck( annotationApiHelper )
)
);
fieldChecks.put(
AnnotationType.MULTI_VALUED_CONSTRAINT_ANNOTATION,
new MultiValuedChecks( constraintHelper, new StaticCheck(), new TypeCheck( constraintHelper ) )
new MultiValuedChecks(
constraintHelper,
new StaticCheck(),
new TypeCheck( constraintHelper ),
new AnnotationParametersSizeLengthCheck( annotationApiHelper ),
new AnnotationParametersPatternCheck( annotationApiHelper ),
new AnnotationParametersScriptAssertCheck( annotationApiHelper ),
new AnnotationParametersDigitsCheck( annotationApiHelper ),
new AnnotationParametersDecimalMinMaxCheck( annotationApiHelper )
)
);
fieldChecks.put(
AnnotationType.GRAPH_VALIDATION_ANNOTATION,
Expand All @@ -70,13 +91,32 @@ public ConstraintCheckFactory(Types typeUtils, ConstraintHelper constraintHelper
methodChecks = CollectionHelper.newHashMap();
methodChecks.put(
AnnotationType.CONSTRAINT_ANNOTATION,
new SingleValuedChecks( new GetterCheck( methodConstraintsSupported ), new StaticCheck(), new MethodAnnotationCheck( constraintHelper ),
new TypeCheck( constraintHelper ) )
new SingleValuedChecks(
new GetterCheck( methodConstraintsSupported ),
new StaticCheck(),
new MethodAnnotationCheck( constraintHelper ),
new TypeCheck( constraintHelper ),
new AnnotationParametersSizeLengthCheck( annotationApiHelper ),
new AnnotationParametersPatternCheck( annotationApiHelper ),
new AnnotationParametersScriptAssertCheck( annotationApiHelper ),
new AnnotationParametersDigitsCheck( annotationApiHelper ),
new AnnotationParametersDecimalMinMaxCheck( annotationApiHelper )
)
);
methodChecks.put(
AnnotationType.MULTI_VALUED_CONSTRAINT_ANNOTATION, new MultiValuedChecks(
constraintHelper, new GetterCheck( methodConstraintsSupported ), new StaticCheck(), new MethodAnnotationCheck( constraintHelper ),
new TypeCheck( constraintHelper ) )
AnnotationType.MULTI_VALUED_CONSTRAINT_ANNOTATION,
new MultiValuedChecks(
constraintHelper,
new GetterCheck( methodConstraintsSupported ),
new StaticCheck(),
new MethodAnnotationCheck( constraintHelper ),
new TypeCheck( constraintHelper ),
new AnnotationParametersSizeLengthCheck( annotationApiHelper ),
new AnnotationParametersPatternCheck( annotationApiHelper ),
new AnnotationParametersScriptAssertCheck( annotationApiHelper ),
new AnnotationParametersDigitsCheck( annotationApiHelper ),
new AnnotationParametersDecimalMinMaxCheck( annotationApiHelper )
)
);
methodChecks.put(
AnnotationType.GRAPH_VALIDATION_ANNOTATION,
Expand All @@ -88,11 +128,26 @@ constraintHelper, new GetterCheck( methodConstraintsSupported ), new StaticCheck
annotationTypeChecks = CollectionHelper.newHashMap();
annotationTypeChecks.put(
AnnotationType.CONSTRAINT_ANNOTATION,
new SingleValuedChecks( new AnnotationTypeCheck( constraintHelper ) )
new SingleValuedChecks(
new AnnotationTypeCheck( constraintHelper ),
new AnnotationParametersSizeLengthCheck( annotationApiHelper ),
new AnnotationParametersPatternCheck( annotationApiHelper ),
new AnnotationParametersScriptAssertCheck( annotationApiHelper ),
new AnnotationParametersDigitsCheck( annotationApiHelper ),
new AnnotationParametersDecimalMinMaxCheck( annotationApiHelper )
)
);
annotationTypeChecks.put(
AnnotationType.MULTI_VALUED_CONSTRAINT_ANNOTATION,
new MultiValuedChecks( constraintHelper, new AnnotationTypeCheck( constraintHelper ) )
new MultiValuedChecks(
constraintHelper,
new AnnotationTypeCheck( constraintHelper ),
new AnnotationParametersSizeLengthCheck( annotationApiHelper ),
new AnnotationParametersPatternCheck( annotationApiHelper ),
new AnnotationParametersScriptAssertCheck( annotationApiHelper ),
new AnnotationParametersDigitsCheck( annotationApiHelper ),
new AnnotationParametersDecimalMinMaxCheck( annotationApiHelper )
)
);
annotationTypeChecks.put(
AnnotationType.CONSTRAINT_META_ANNOTATION,
Expand All @@ -108,11 +163,27 @@ constraintHelper, new GetterCheck( methodConstraintsSupported ), new StaticCheck

nonAnnotationTypeChecks = CollectionHelper.newHashMap();
nonAnnotationTypeChecks.put(
AnnotationType.CONSTRAINT_ANNOTATION, new SingleValuedChecks( new TypeCheck( constraintHelper ) )
AnnotationType.CONSTRAINT_ANNOTATION,
new SingleValuedChecks(
new TypeCheck( constraintHelper ),
new AnnotationParametersSizeLengthCheck( annotationApiHelper ),
new AnnotationParametersPatternCheck( annotationApiHelper ),
new AnnotationParametersScriptAssertCheck( annotationApiHelper ),
new AnnotationParametersDigitsCheck( annotationApiHelper ),
new AnnotationParametersDecimalMinMaxCheck( annotationApiHelper )
)
);
nonAnnotationTypeChecks.put(
AnnotationType.MULTI_VALUED_CONSTRAINT_ANNOTATION,
new MultiValuedChecks( constraintHelper, new TypeCheck( constraintHelper ) )
new MultiValuedChecks(
constraintHelper,
new TypeCheck( constraintHelper ),
new AnnotationParametersSizeLengthCheck( annotationApiHelper ),
new AnnotationParametersPatternCheck( annotationApiHelper ),
new AnnotationParametersScriptAssertCheck( annotationApiHelper ),
new AnnotationParametersDigitsCheck( annotationApiHelper ),
new AnnotationParametersDecimalMinMaxCheck( annotationApiHelper )
)
);
nonAnnotationTypeChecks.put( AnnotationType.NO_CONSTRAINT_ANNOTATION, NULL_CHECKS );
nonAnnotationTypeChecks.put(
Expand All @@ -135,7 +206,6 @@ AnnotationType.CONSTRAINT_ANNOTATION, new SingleValuedChecks( new TypeCheck( con
* the given element.
*/
public ConstraintChecks getConstraintChecks(Element annotatedElement, AnnotationMirror annotation) {

AnnotationType annotationType = constraintHelper.getAnnotationType( annotation );

switch ( annotatedElement.getKind() ) {
Expand Down
@@ -0,0 +1,87 @@
/*
* Hibernate Validator, declare and validate application constraints
*
* License: Apache License, Version 2.0
* See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>.
*/
package org.hibernate.validator.ap.checks.annotationparameters;

import org.hibernate.validator.ap.checks.AbstractConstraintCheck;
import org.hibernate.validator.ap.checks.ConstraintCheckError;
import org.hibernate.validator.ap.util.AnnotationApiHelper;

import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

/**
* Checks that parameters used on annotation are valid.
*
* @author Marko Bekhta
*/
public abstract class AnnotationParametersAbstractCheck extends AbstractConstraintCheck {

protected final AnnotationApiHelper annotationApiHelper;

private Set<String> annotationClasses;

public AnnotationParametersAbstractCheck(AnnotationApiHelper annotationApiHelper, String... annotationClass) {
this.annotationApiHelper = annotationApiHelper;
this.annotationClasses = new HashSet<String>( Arrays.asList( annotationClass ) );
}

@Override
public Set<ConstraintCheckError> checkField(VariableElement element, AnnotationMirror annotation) {
return checkAnnotation( element, annotation );
}

@Override
public Set<ConstraintCheckError> checkMethod(ExecutableElement element, AnnotationMirror annotation) {
return checkAnnotation( element, annotation );
}

@Override
public Set<ConstraintCheckError> checkAnnotationType(TypeElement element, AnnotationMirror annotation) {
return checkAnnotation( element, annotation );
}

@Override
public Set<ConstraintCheckError> checkNonAnnotationType(TypeElement element, AnnotationMirror annotation) {
return checkAnnotation( element, annotation );
}

/**
* Verify that this check class can process such annotation.
*
* @param annotation annotation you want to process by this class
* @return {@code true} if such annotation can be processed, {@code false} otherwise.
*/
private boolean canCheckThisAnnotation(AnnotationMirror annotation) {
return annotationClasses.contains( annotation.getAnnotationType().asElement().toString() );
}


private Set<ConstraintCheckError> checkAnnotation(Element element, AnnotationMirror annotation) {
if ( canCheckThisAnnotation( annotation ) ) {
return doCheck( element, annotation );
}
return Collections.emptySet();
}

/**
* Method which actually performs the validation of the annotation parameters.
*
* @param element annotated element
* @param annotation annotation to process
* @return a set of {@link ConstraintCheckError} errors if there are any validation issues with the annotation
* parameters
*/
protected abstract Set<ConstraintCheckError> doCheck(Element element, AnnotationMirror annotation);

}
@@ -0,0 +1,48 @@
/*
* Hibernate Validator, declare and validate application constraints
*
* License: Apache License, Version 2.0
* See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>.
*/
package org.hibernate.validator.ap.checks.annotationparameters;

import org.hibernate.validator.ap.checks.ConstraintCheckError;
import org.hibernate.validator.ap.util.AnnotationApiHelper;
import org.hibernate.validator.ap.util.CollectionHelper;

import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.Set;

/**
* Checks that the parameters used on {@code javax.validation.constraints.DecimalMin} and
* {@code javax.validation.constraints.DecimalMax} annotations are valid.
*
* @author Marko Bekhta
*/
public class AnnotationParametersDecimalMinMaxCheck extends AnnotationParametersAbstractCheck {

public AnnotationParametersDecimalMinMaxCheck(AnnotationApiHelper annotationApiHelper) {
super( annotationApiHelper, "javax.validation.constraints.DecimalMin", "javax.validation.constraints.DecimalMax" );
}

@Override
protected Set<ConstraintCheckError> doCheck(Element element, AnnotationMirror annotation) {
String value = (String) annotationApiHelper.getAnnotationValue( annotation, "value" ).getValue();

try {
new BigDecimal( value );
return Collections.emptySet();
}
catch (NumberFormatException nfe) {
return CollectionHelper.asSet(
new ConstraintCheckError(
element, annotation, "INVALID_DECIMAL_MIN_MAX_ANNOTATION_PARAMETERS"
)
);
}

}
}
@@ -0,0 +1,44 @@
/*
* Hibernate Validator, declare and validate application constraints
*
* License: Apache License, Version 2.0
* See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>.
*/
package org.hibernate.validator.ap.checks.annotationparameters;

import org.hibernate.validator.ap.checks.ConstraintCheckError;
import org.hibernate.validator.ap.util.AnnotationApiHelper;
import org.hibernate.validator.ap.util.CollectionHelper;

import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import java.util.Collections;
import java.util.Set;

/**
* Checks that the parameters used on {@code javax.validation.constraints.Digits} annotations are valid.
*
* @author Marko Bekhta
*/
public class AnnotationParametersDigitsCheck extends AnnotationParametersAbstractCheck {

public AnnotationParametersDigitsCheck(AnnotationApiHelper annotationApiHelper) {
super( annotationApiHelper, "javax.validation.constraints.Digits" );
}

@Override
protected Set<ConstraintCheckError> doCheck(Element element, AnnotationMirror annotation) {
Integer integer = (Integer) annotationApiHelper.getAnnotationValue( annotation, "integer" ).getValue();
Integer fraction = (Integer) annotationApiHelper.getAnnotationValue( annotation, "fraction" ).getValue();

if ( ( integer < 0 ) || ( fraction < 0 ) ) {
return CollectionHelper.asSet(
new ConstraintCheckError(
element, annotation, "INVALID_DIGITS_ANNOTATION_PARAMETERS"
)
);
}

return Collections.emptySet();
}
}
@@ -0,0 +1,48 @@
/*
* Hibernate Validator, declare and validate application constraints
*
* License: Apache License, Version 2.0
* See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>.
*/
package org.hibernate.validator.ap.checks.annotationparameters;

import org.hibernate.validator.ap.checks.ConstraintCheckError;
import org.hibernate.validator.ap.util.AnnotationApiHelper;
import org.hibernate.validator.ap.util.CollectionHelper;

import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import java.util.Collections;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

/**
* Checks that the parameters used on {@code javax.validation.constraints.Pattern} annotations are valid.
*
* @author Marko Bekhta
*/
public class AnnotationParametersPatternCheck extends AnnotationParametersAbstractCheck {

public AnnotationParametersPatternCheck(AnnotationApiHelper annotationApiHelper) {
super( annotationApiHelper, "javax.validation.constraints.Pattern" );
}

@Override
protected Set<ConstraintCheckError> doCheck(Element element, AnnotationMirror annotation) {
String regexp = (String) annotationApiHelper.getAnnotationValue( annotation, "regexp" ).getValue();

try {
Pattern.compile( regexp );
}
catch (PatternSyntaxException e) {
return CollectionHelper.asSet(
new ConstraintCheckError(
element, annotation, "INVALID_PATTERN_ANNOTATION_PARAMETERS"
)
);
}

return Collections.emptySet();
}
}

0 comments on commit 1b4b28f

Please sign in to comment.