mirror of
https://github.com/jlengrand/quarkus.git
synced 2026-03-10 08:41:22 +00:00
hibernate validator: Remember annotated interface methods
resolves #1888
This commit is contained in:
@@ -5,8 +5,10 @@ import static io.quarkus.deployment.annotations.ExecutionTime.STATIC_INIT;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@@ -30,6 +32,7 @@ import org.jboss.jandex.AnnotationTarget;
|
||||
import org.jboss.jandex.ClassInfo;
|
||||
import org.jboss.jandex.DotName;
|
||||
import org.jboss.jandex.IndexView;
|
||||
import org.jboss.jandex.MethodInfo;
|
||||
import org.jboss.jandex.Type;
|
||||
|
||||
import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
|
||||
@@ -144,6 +147,7 @@ class HibernateValidatorProcessor {
|
||||
consideredAnnotations.add(VALIDATE_ON_EXECUTION);
|
||||
|
||||
Set<DotName> classNamesToBeValidated = new HashSet<>();
|
||||
Map<DotName, Set<String>> inheritedAnnotationsToBeValidated = new HashMap<>();
|
||||
|
||||
for (DotName consideredAnnotation : consideredAnnotations) {
|
||||
Collection<AnnotationInstance> annotationInstances = indexView.getAnnotations(consideredAnnotation);
|
||||
@@ -160,6 +164,8 @@ class HibernateValidatorProcessor {
|
||||
reflectiveMethods.produce(new ReflectiveMethodBuildItem(annotation.target().asMethod()));
|
||||
contributeClassMarkedForCascadingValidation(classNamesToBeValidated, indexView, consideredAnnotation,
|
||||
annotation.target().asMethod().returnType());
|
||||
contributeMethodsWithInheritedValidation(inheritedAnnotationsToBeValidated, indexView,
|
||||
annotation.target().asMethod());
|
||||
} else if (annotation.target().kind() == AnnotationTarget.Kind.METHOD_PARAMETER) {
|
||||
contributeClass(classNamesToBeValidated, indexView,
|
||||
annotation.target().asMethodParameter().method().declaringClass().name());
|
||||
@@ -168,6 +174,8 @@ class HibernateValidatorProcessor {
|
||||
// FIXME this won't work in the case of synthetic parameters
|
||||
annotation.target().asMethodParameter().method().parameters()
|
||||
.get(annotation.target().asMethodParameter().position()));
|
||||
contributeMethodsWithInheritedValidation(inheritedAnnotationsToBeValidated, indexView,
|
||||
annotation.target().asMethodParameter().method());
|
||||
} else if (annotation.target().kind() == AnnotationTarget.Kind.CLASS) {
|
||||
contributeClass(classNamesToBeValidated, indexView, annotation.target().asClass().name());
|
||||
// no need for reflection in the case of a class level constraint
|
||||
@@ -183,7 +191,8 @@ class HibernateValidatorProcessor {
|
||||
annotationsTransformers
|
||||
.produce(new AnnotationsTransformerBuildItem(
|
||||
new MethodValidatedAnnotationsTransformer(consideredAnnotations,
|
||||
additionalJaxRsMethodAnnotationsDotNames)));
|
||||
additionalJaxRsMethodAnnotationsDotNames,
|
||||
inheritedAnnotationsToBeValidated)));
|
||||
|
||||
Set<Class<?>> classesToBeValidated = new HashSet<>();
|
||||
for (DotName className : classNamesToBeValidated) {
|
||||
@@ -245,6 +254,16 @@ class HibernateValidatorProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
private static void contributeMethodsWithInheritedValidation(Map<DotName, Set<String>> inheritedAnnotationsToBeValidated,
|
||||
IndexView indexView, MethodInfo method) {
|
||||
ClassInfo clazz = method.declaringClass();
|
||||
if (Modifier.isInterface(clazz.flags())) {
|
||||
// Remember annotated interface methods that must be validated
|
||||
inheritedAnnotationsToBeValidated.computeIfAbsent(clazz.name(), k -> new HashSet<String>())
|
||||
.add(method.name().toString());
|
||||
}
|
||||
}
|
||||
|
||||
private static DotName getClassName(Type type) {
|
||||
switch (type.kind()) {
|
||||
case CLASS:
|
||||
|
||||
@@ -3,9 +3,11 @@ package io.quarkus.hibernate.validator.deployment;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jboss.jandex.AnnotationTarget.Kind;
|
||||
import org.jboss.jandex.ClassInfo;
|
||||
import org.jboss.jandex.DotName;
|
||||
import org.jboss.jandex.MethodInfo;
|
||||
|
||||
@@ -30,10 +32,14 @@ public class MethodValidatedAnnotationsTransformer implements AnnotationsTransfo
|
||||
|
||||
private final Set<DotName> consideredAnnotations;
|
||||
private final Collection<DotName> effectiveJaxRsMethodDefiningAnnotations;
|
||||
private final Map<DotName, Set<String>> inheritedAnnotationsToBeValidated;
|
||||
|
||||
MethodValidatedAnnotationsTransformer(Set<DotName> consideredAnnotations,
|
||||
Collection<DotName> additionalJaxRsMethodAnnotationsDotNames) {
|
||||
Collection<DotName> additionalJaxRsMethodAnnotationsDotNames,
|
||||
Map<DotName, Set<String>> inheritedAnnotationsToBeValidated) {
|
||||
this.consideredAnnotations = consideredAnnotations;
|
||||
this.inheritedAnnotationsToBeValidated = inheritedAnnotationsToBeValidated;
|
||||
|
||||
this.effectiveJaxRsMethodDefiningAnnotations = new ArrayList<>(
|
||||
JAXRS_METHOD_ANNOTATIONS.length + additionalJaxRsMethodAnnotationsDotNames.size());
|
||||
effectiveJaxRsMethodDefiningAnnotations.addAll(Arrays.asList(JAXRS_METHOD_ANNOTATIONS));
|
||||
@@ -60,6 +66,15 @@ public class MethodValidatedAnnotationsTransformer implements AnnotationsTransfo
|
||||
|
||||
private boolean requiresValidation(MethodInfo method) {
|
||||
if (method.annotations().isEmpty()) {
|
||||
// This method has no annotations of its own: look for inherited annotations
|
||||
ClassInfo clazz = method.declaringClass();
|
||||
String methodName = method.name().toString();
|
||||
for (Map.Entry<DotName, Set<String>> validatedMethod : inheritedAnnotationsToBeValidated.entrySet()) {
|
||||
if (clazz.interfaceNames().contains(validatedMethod.getKey())
|
||||
&& validatedMethod.getValue().contains(methodName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,9 @@ public class HibernateValidatorTestResource
|
||||
@Inject
|
||||
GreetingService greetingService;
|
||||
|
||||
@Inject
|
||||
ZipCodeService zipCodeResource;
|
||||
|
||||
@GET
|
||||
@Path("/basic-features")
|
||||
@Produces(MediaType.TEXT_PLAIN)
|
||||
@@ -132,6 +135,25 @@ public class HibernateValidatorTestResource
|
||||
return result.build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/test-inherited-constraints")
|
||||
@Produces(MediaType.TEXT_PLAIN)
|
||||
public String testInheritedConstraints() {
|
||||
ResultBuilder result = new ResultBuilder();
|
||||
|
||||
zipCodeResource.echoZipCode("12345");
|
||||
|
||||
result.append(formatViolations(Collections.emptySet()));
|
||||
|
||||
try {
|
||||
zipCodeResource.echoZipCode("1234");
|
||||
} catch (ConstraintViolationException e) {
|
||||
result.append(formatViolations(e.getConstraintViolations()));
|
||||
}
|
||||
|
||||
return result.build();
|
||||
}
|
||||
|
||||
private String formatViolations(Set<? extends ConstraintViolation<?>> violations) {
|
||||
if (violations.isEmpty()) {
|
||||
return "passed";
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package io.quarkus.it.hibernate.validator;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
public interface ZipCodeService {
|
||||
|
||||
public String echoZipCode(@NotNull @Size(min = 5, max = 5) String zipCode);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package io.quarkus.it.hibernate.validator;
|
||||
|
||||
import javax.enterprise.context.ApplicationScoped;
|
||||
|
||||
@ApplicationScoped
|
||||
public class ZipCodeServiceImpl implements ZipCodeService {
|
||||
|
||||
@Override
|
||||
public String echoZipCode(String zipCode) {
|
||||
return zipCode;
|
||||
}
|
||||
}
|
||||
@@ -103,4 +103,16 @@ public class HibernateValidatorFunctionalityTest {
|
||||
.then()
|
||||
.body(is(expected.toString()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInheritedConstraints() {
|
||||
StringBuilder expected = new StringBuilder();
|
||||
expected.append("passed").append("\n")
|
||||
.append("failed: echoZipCode.arg0 (size must be between 5 and 5)");
|
||||
|
||||
RestAssured.when()
|
||||
.get("/hibernate-validator/test/test-inherited-constraints")
|
||||
.then()
|
||||
.body(is(expected.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user