This is an automated email from the ASF dual-hosted git repository. jungm pushed a commit to branch BVAL-222 in repository https://gitbox.apache.org/repos/asf/bval.git
commit 08f8bd001e6191c137b10f7f42ec7c2138d8b4f9 Author: Markus Jung <[email protected]> AuthorDate: Tue Jan 28 13:32:09 2025 +0100 BVAL222 - enable BValInterceptor when constraints are only placed on parent classes --- .../java/org/apache/bval/cdi/BValExtension.java | 105 ++++++++++++++------- 1 file changed, 72 insertions(+), 33 deletions(-) diff --git a/bval-jsr/src/main/java/org/apache/bval/cdi/BValExtension.java b/bval-jsr/src/main/java/org/apache/bval/cdi/BValExtension.java index ae02f47..9fd9640 100644 --- a/bval-jsr/src/main/java/org/apache/bval/cdi/BValExtension.java +++ b/bval-jsr/src/main/java/org/apache/bval/cdi/BValExtension.java @@ -19,11 +19,17 @@ package org.apache.bval.cdi; import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Executable; import java.lang.reflect.Modifier; +import java.lang.reflect.Parameter; import java.lang.reflect.Type; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; +import java.util.LinkedList; +import java.util.Queue; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; @@ -33,10 +39,8 @@ import jakarta.enterprise.context.spi.CreationalContext; import jakarta.enterprise.event.Observes; import jakarta.enterprise.inject.spi.AfterBeanDiscovery; import jakarta.enterprise.inject.spi.AfterDeploymentValidation; -import jakarta.enterprise.inject.spi.Annotated; import jakarta.enterprise.inject.spi.AnnotatedType; import jakarta.enterprise.inject.spi.Bean; -import jakarta.enterprise.inject.spi.BeanAttributes; import jakarta.enterprise.inject.spi.BeanManager; import jakarta.enterprise.inject.spi.BeforeBeanDiscovery; import jakarta.enterprise.inject.spi.CDI; @@ -128,13 +132,25 @@ public class BValExtension implements Extension { final int modifiers = javaClass.getModifiers(); if (!javaClass.isInterface() && !javaClass.isAnonymousClass() && !Modifier.isFinal(modifiers) && !Modifier.isAbstract(modifiers)) { try { - if (hasValidation(annotatedType) - || hasValidationAnnotation(annotatedType.getMethods()) - || hasValidationAnnotation(annotatedType.getConstructors()) - || Stream.concat(annotatedType.getMethods().stream(), annotatedType.getConstructors().stream()) - .flatMap(it -> it.getParameters().stream()) - .anyMatch(this::hasValidation)) { - pat.setAnnotatedType(new BValAnnotatedType<>(annotatedType)); + Queue<Class<?>> toProcess = new LinkedList<>(); + toProcess.add(annotatedType.getJavaClass()); + + while (!toProcess.isEmpty()) { + Class<?> now = toProcess.poll(); + if (hasValidation(now) + || hasValidation(now.getMethods()) || hasValidation(now.getConstructors()) + || hasParamsWithValidation(now.getMethods()) || hasParamsWithValidation(now.getConstructors())) { + pat.setAnnotatedType(new BValAnnotatedType<>(annotatedType)); + + break; + } + + // Nothing found, collect superclass/interface and repeat (See BVAL-222) + if (now.getSuperclass() != Object.class) { + toProcess.add(now.getSuperclass()); + } + + toProcess.addAll(Arrays.asList(now.getInterfaces())); } } catch (final Exception e) { if (e instanceof ValidationException) { @@ -201,32 +217,55 @@ public class BValExtension implements Extension { notBValAnnotation.clear(); } - private boolean hasValidationAnnotation(final Collection<? extends Annotated> annotateds) { - return annotateds.stream().anyMatch(this::hasValidation); + private boolean hasValidation(final AnnotatedElement[] elements) { + for (int i = 0; i < elements.length; i++) { + if (hasValidation(elements[i])) { + return true; + } + } + + return false; } - private boolean hasValidation(final Annotated m) { - return m.getAnnotations().stream() - .anyMatch(it -> { - final Class<? extends Annotation> type = it.annotationType(); - if (type == ValidateOnExecution.class || type == Valid.class) { - return true; - } - if (isSkippedAnnotation(type)) { - return false; - } - if (type.getName().startsWith("jakarta.validation.constraints")) { - return true; - } - if (notBValAnnotation.contains(type)) { // more likely so faster first - return false; - } - if (potentiallyBValAnnotation.contains(type)) { - return true; - } - cacheIsBvalAnnotation(type); - return potentiallyBValAnnotation.contains(type); - }); + private boolean hasParamsWithValidation(Executable[] executables) { + for (int i = 0; i < executables.length; i++) { + Parameter[] params = executables[i].getParameters(); + for (int j = 0; j < params.length; j++) { + if (hasValidation(params[j])) { + return true; + } + } + } + + return false; + } + + private boolean hasValidation(final AnnotatedElement element) { + Annotation[] annotations = element.getAnnotations(); + for (int i = 0; i < annotations.length; i++) { + final Class<? extends Annotation> type = annotations[i].annotationType(); + if (type == ValidateOnExecution.class || type == Valid.class) { + return true; + } + if (isSkippedAnnotation(type)) { + continue; + } + if (type.getName().startsWith("jakarta.validation.constraints")) { + return true; + } + if (notBValAnnotation.contains(type)) { // more likely so faster first + continue; + } + if (potentiallyBValAnnotation.contains(type)) { + return true; + } + cacheIsBvalAnnotation(type); + if (potentiallyBValAnnotation.contains(type)) { + return true; + } + } + + return false; } private boolean isSkippedAnnotation(final Class<? extends Annotation> type) {
