Skip to content

Commit 4aba196

Browse files
marko-bekhtagsmet
authored andcommitted
HV-1395 Changing unwrapping rules in AP
1 parent 1d5840d commit 4aba196

File tree

7 files changed

+89
-27
lines changed

7 files changed

+89
-27
lines changed

annotation-processor/src/main/java/org/hibernate/validator/ap/internal/checks/TypeCheck.java

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import java.util.Set;
1212

1313
import javax.lang.model.element.AnnotationMirror;
14-
import javax.lang.model.element.AnnotationValue;
1514
import javax.lang.model.element.Element;
1615
import javax.lang.model.element.ExecutableElement;
1716
import javax.lang.model.element.Name;
@@ -22,6 +21,7 @@
2221
import javax.lang.model.util.Types;
2322

2423
import org.hibernate.validator.ap.internal.util.AnnotationApiHelper;
24+
import org.hibernate.validator.ap.internal.util.AnnotationApiHelper.UnwrapMode;
2525
import org.hibernate.validator.ap.internal.util.CollectionHelper;
2626
import org.hibernate.validator.ap.internal.util.ConstraintHelper;
2727
import org.hibernate.validator.ap.internal.util.ConstraintHelper.AnnotationProcessorValidationTarget;
@@ -74,11 +74,23 @@ public Set<ConstraintCheckIssue> checkNonAnnotationType(TypeElement element, Ann
7474
}
7575

7676
private Set<ConstraintCheckIssue> checkInternal(Element element, AnnotationMirror annotation, TypeMirror type, String messageKey) {
77-
TypeMirror typeToCheck = usesUnwrapping( annotation, type ) ? getUnwrappedType( type ) : type;
78-
if ( !isAnnotationAllowedForType( annotation, typeToCheck ) ) {
77+
Optional<TypeMirror> typeToCheck = usesUnwrapping( annotation, type ) ?
78+
getUnwrappedType( type ) :
79+
Optional.of( type );
80+
if ( typeToCheck.isPresent() ) {
81+
if ( !isAnnotationAllowedForType( annotation, typeToCheck.get() ) ) {
82+
return CollectionHelper.asSet(
83+
ConstraintCheckIssue.error(
84+
element, annotation, messageKey,
85+
annotation.getAnnotationType().asElement().getSimpleName()
86+
) );
87+
}
88+
}
89+
else {
90+
// it means that the type was marked for unwrapping but unwrapped value type was not found
7991
return CollectionHelper.asSet(
80-
ConstraintCheckIssue.error(
81-
element, annotation, messageKey,
92+
ConstraintCheckIssue.warning(
93+
element, annotation, "NOT_FOUND_UNWRAPPED_TYPE",
8294
annotation.getAnnotationType().asElement().getSimpleName()
8395
) );
8496
}
@@ -91,30 +103,22 @@ private boolean isAnnotationAllowedForType(AnnotationMirror annotation, TypeMirr
91103
}
92104

93105
private boolean usesUnwrapping(AnnotationMirror annotationMirror, TypeMirror typeMirror) {
106+
UnwrapMode mode = annotationApiHelper.determineUnwrapMode( annotationMirror );
107+
if ( UnwrapMode.SKIP.equals( mode ) ) {
108+
return false;
109+
}
110+
94111
//need to check if this annotation is not on one of the types that are automatically unwrapped:
95112
if ( constraintHelper.isSupportedForUnwrappingByDefault( getQualifiedName( typeMirror ) ) ) {
96113
return true;
97114
}
98115

99116
//otherwise look for Unwrapping type in payload:
100-
return annotationApiHelper.getAnnotationArrayValue( annotationMirror, "payload" ).stream()
101-
.map( AnnotationValue::getValue )
102-
.map( type -> (TypeMirror) type )
103-
.map( typeUtils::asElement )
104-
.map( elem -> ( (TypeElement) elem ).getQualifiedName() )
105-
.filter( name -> name.toString().equals( "javax.validation.valueextraction.Unwrapping.Unwrap" ) )
106-
.findAny().isPresent();
117+
return UnwrapMode.UNWRAP.equals( mode );
107118
}
108119

109-
private TypeMirror getUnwrappedType(TypeMirror type) {
110-
Optional<TypeMirror> optional = constraintHelper.getUnwrappedToByDefault( getQualifiedName( type ) );
111-
if ( optional.isPresent() ) {
112-
return optional.get();
113-
}
114-
else {
115-
//TODO: need to find a way to check for unwrapping
116-
return type;
117-
}
120+
private Optional<TypeMirror> getUnwrappedType(TypeMirror type) {
121+
return constraintHelper.getUnwrappedToByDefault( getQualifiedName( type ) );
118122
}
119123

120124
private Name getQualifiedName(TypeMirror typeMirror) {

annotation-processor/src/main/java/org/hibernate/validator/ap/internal/util/AnnotationApiHelper.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import javax.lang.model.element.AnnotationMirror;
1717
import javax.lang.model.element.AnnotationValue;
1818
import javax.lang.model.element.ExecutableElement;
19+
import javax.lang.model.element.Name;
1920
import javax.lang.model.element.TypeElement;
2021
import javax.lang.model.type.DeclaredType;
2122
import javax.lang.model.type.TypeKind;
@@ -345,4 +346,38 @@ public boolean isClass(TypeMirror typeMirror) {
345346
return TypeKind.DECLARED.equals( typeMirror.getKind() ) && ( (DeclaredType) typeMirror ).asElement().getKind().isClass();
346347
}
347348

349+
/**
350+
* Checks the annotation's payload for unwrapping option ({@code javax.validation.valueextraction.Unwrapping.Unwrap},
351+
* {@code javax.validation.valueextraction.Unwrapping.Skip}) of constraint.
352+
*
353+
* @param annotationMirror constraint annotation mirror under check
354+
* @return unwrapping option, if one is present in the annotation payload, {@link UnwrapMode#NONE} otherwise
355+
*/
356+
public UnwrapMode determineUnwrapMode(AnnotationMirror annotationMirror) {
357+
return getAnnotationArrayValue( annotationMirror, "payload" ).stream()
358+
.map( AnnotationValue::getValue )
359+
.map( type -> (TypeMirror) type )
360+
.map( typeUtils::asElement )
361+
.map( elem -> ( (TypeElement) elem ).getQualifiedName() )
362+
.filter( name -> name.toString().startsWith( "javax.validation.valueextraction.Unwrapping." ) )
363+
.map( UnwrapMode::of )
364+
.findAny().orElse( UnwrapMode.NONE );
365+
}
366+
367+
public enum UnwrapMode {
368+
UNWRAP, SKIP, NONE;
369+
370+
public static UnwrapMode of(Name qualifiedName) {
371+
if ( "javax.validation.valueextraction.Unwrapping.Unwrap".equals( qualifiedName.toString() ) ) {
372+
return UNWRAP;
373+
}
374+
else if ( "javax.validation.valueextraction.Unwrapping.Skip".equals( qualifiedName.toString() ) ) {
375+
return SKIP;
376+
}
377+
else {
378+
return NONE;
379+
}
380+
}
381+
}
382+
348383
}

annotation-processor/src/main/resources/org/hibernate/validator/ap/ValidationProcessorMessages.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
ONLY_GETTERS_MAY_BE_ANNOTATED=Constraint annotations must not be specified at methods, which are no valid JavaBeans getter methods.
44
NOT_SUPPORTED_TYPE=The annotation @{0} is disallowed for this data type.
55
NOT_SUPPORTED_RETURN_TYPE=The annotation @{0} is disallowed for the return type of this method.
6+
NOT_FOUND_UNWRAPPED_TYPE=Constraint was marked for unwrapping but no unwrapped type was registered by Annotation Processor.
67
ONLY_CONSTRAINT_ANNOTATIONS_MAY_BE_ANNOTATED=Constraint annotations must not be specified at annotation types, which are no constraint annotation types themselves.
78
STATIC_METHODS_MAY_NOT_BE_ANNOTATED=Only non-static methods may be annotated with constraint annotations.
89
STATIC_FIELDS_MAY_NOT_BE_ANNOTATED=Only non-static fields may be annotated with constraint annotations.

annotation-processor/src/test/java/org/hibernate/validator/ap/AnnotationParametersValidationTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,8 @@ public void usingIncompatibleUnwrappingCombination() {
305305
assertFalse( compilationResult );
306306
assertThatDiagnosticsMatch(
307307
diagnostics,
308-
new DiagnosticExpectation( Kind.ERROR, 28 )
308+
new DiagnosticExpectation( Kind.ERROR, 29 ),
309+
new DiagnosticExpectation( Kind.WARNING, 35 )
309310
);
310311
}
311312

annotation-processor/src/test/java/org/hibernate/validator/ap/ConstraintValidationProcessorTest.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -676,9 +676,13 @@ public void unwrappingConstraints() {
676676
assertFalse( compilationResult );
677677
assertThatDiagnosticsMatch(
678678
diagnostics,
679-
new DiagnosticExpectation( Kind.ERROR, 32 ),
680-
new DiagnosticExpectation( Kind.ERROR, 35 ),
681-
new DiagnosticExpectation( Kind.ERROR, 38 )
679+
new DiagnosticExpectation( Kind.ERROR, 33 ),
680+
new DiagnosticExpectation( Kind.ERROR, 36 ),
681+
new DiagnosticExpectation( Kind.ERROR, 39 ),
682+
new DiagnosticExpectation( Kind.ERROR, 42 ),
683+
new DiagnosticExpectation( Kind.ERROR, 45 ),
684+
new DiagnosticExpectation( Kind.ERROR, 48 ),
685+
new DiagnosticExpectation( Kind.WARNING, 54 )
682686
);
683687
}
684688
}

annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/annotationparameters/InvalidUnwrappingCombination.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import java.lang.annotation.Retention;
1414
import java.lang.annotation.Target;
1515
import java.util.Optional;
16+
import java.util.OptionalInt;
1617

1718
import javax.validation.Constraint;
1819
import javax.validation.ConstraintValidator;
@@ -26,15 +27,15 @@
2627
public class InvalidUnwrappingCombination {
2728

2829
@OptionalConstraint(payload = { Unwrapping.Unwrap.class, Unwrapping.Skip.class })
29-
private final Optional<Integer> number;
30+
private final OptionalInt number;
3031

3132
@OptionalConstraint(payload = { Unwrapping.Skip.class })
3233
private final Optional<Integer> number2;
3334

3435
@OptionalConstraint(payload = { Unwrapping.Unwrap.class })
3536
private final Optional<Integer> number3;
3637

37-
public InvalidUnwrappingCombination(Optional<Integer> number, Optional<Integer> number2, Optional<Integer> number3) {
38+
public InvalidUnwrappingCombination(OptionalInt number, Optional<Integer> number2, Optional<Integer> number3) {
3839
this.number = number;
3940
this.number2 = number2;
4041
this.number3 = number3;

annotation-processor/src/test/java/org/hibernate/validator/ap/testmodel/customconstraints/UnwrappingConstraints.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import javax.validation.constraints.Min;
1414
import javax.validation.constraints.Past;
15+
import javax.validation.valueextraction.Unwrapping;
1516

1617
public class UnwrappingConstraints {
1718

@@ -37,4 +38,19 @@ public class UnwrappingConstraints {
3738

3839
@Past
3940
public OptionalDouble badOptionalDouble;
41+
42+
@Min(value = 10, payload = Unwrapping.Skip.class)
43+
public OptionalInt skipOptionalInt;
44+
45+
@Min(value = 10, payload = Unwrapping.Skip.class)
46+
public OptionalLong skipOptionalLong;
47+
48+
@Min(value = 10, payload = Unwrapping.Skip.class)
49+
public OptionalDouble skipOptionalDouble;
50+
51+
/**
52+
* Warning
53+
*/
54+
@Min(value = 10, payload = Unwrapping.Unwrap.class)
55+
public Integer unwrappedInteger;
4056
}

0 commit comments

Comments
 (0)