From 6b2f04bddc6fac776e751a668a9f947b4d93331b Mon Sep 17 00:00:00 2001 From: Matej Novotny Date: Fri, 3 Mar 2023 13:40:05 +0100 Subject: [PATCH] Arc - Do not validate static members in inner non-static classes for CDI annotations --- .../WrongAnnotationUsageProcessor.java | 80 ++++++++++++++----- 1 file changed, 60 insertions(+), 20 deletions(-) diff --git a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/WrongAnnotationUsageProcessor.java b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/WrongAnnotationUsageProcessor.java index a68213e6271b1..9d33492a7c18b 100644 --- a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/WrongAnnotationUsageProcessor.java +++ b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/WrongAnnotationUsageProcessor.java @@ -7,13 +7,16 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.stream.Collectors; import org.jboss.jandex.AnnotationInstance; import org.jboss.jandex.AnnotationTarget; import org.jboss.jandex.ClassInfo; import org.jboss.jandex.ClassInfo.NestingType; import org.jboss.jandex.DotName; +import org.jboss.jandex.FieldInfo; import org.jboss.jandex.IndexView; +import org.jboss.jandex.MethodInfo; import io.quarkus.arc.deployment.ValidationPhaseBuildItem.ValidationErrorBuildItem; import io.quarkus.arc.processor.Annotations; @@ -72,35 +75,72 @@ void detect(ArcConfig config, ApplicationIndexBuildItem applicationIndex, Custom NestingType nestingType = clazz.nestingType(); if (NestingType.ANONYMOUS == nestingType || NestingType.LOCAL == nestingType || (NestingType.INNER == nestingType && !Modifier.isStatic(clazz.flags()))) { - // Annotations declared on the class, incl. the annotations added via transformers - Collection classAnnotations = transformedAnnotations.getAnnotations(clazz); - if (classAnnotations.isEmpty() && clazz.annotationsMap().isEmpty()) { - continue; - } - if (scopeAnnotations.isScopeIn(classAnnotations)) { + // Annotations declared on the class level, incl. the annotations added via transformers + List classLevelAnnotations = transformedAnnotations.getAnnotations(clazz).stream() + .filter(a -> a.target().kind() == AnnotationTarget.Kind.CLASS).collect(Collectors.toList()); + if (scopeAnnotations.isScopeIn(classLevelAnnotations)) { validationErrors.produce(new ValidationErrorBuildItem( new IllegalStateException(String.format( "The %s class %s has a scope annotation but it must be ignored per the CDI rules", clazz.nestingType().toString(), clazz.name().toString())))); - } else if (clazz.annotationsMap().containsKey(DotNames.OBSERVES)) { - validationErrors.produce(new ValidationErrorBuildItem( - new IllegalStateException(String.format( - "The %s class %s declares an observer method but it must be ignored per the CDI rules", - clazz.nestingType().toString(), clazz.name().toString())))); - } else if (clazz.annotationsMap().containsKey(DotNames.PRODUCES)) { - validationErrors.produce(new ValidationErrorBuildItem( - new IllegalStateException(String.format( - "The %s class %s declares a producer but it must be ignored per the CDI rules", - clazz.nestingType().toString(), clazz.name().toString())))); - } else if (Annotations.containsAny(classAnnotations, interceptorResolverBuildItem.getInterceptorBindings()) - || Annotations.containsAny(clazz.annotations(), - interceptorResolverBuildItem.getInterceptorBindings())) { - // detect interceptor bindings on nested classes + } else if (Annotations.containsAny(classLevelAnnotations, + interceptorResolverBuildItem.getInterceptorBindings())) { + // detect interceptor bindings declared at nested class level validationErrors.produce(new ValidationErrorBuildItem( new IllegalStateException(String.format( "The %s class %s declares an interceptor binding but it must be ignored per CDI rules", clazz.nestingType().toString(), clazz.name().toString())))); } + + // iterate over methods and verify those + // since JDK 16, you can have static method inside inner non-static class - skip those + for (MethodInfo methodInfo : clazz.methods()) { + if (Modifier.isStatic(methodInfo.flags())) { + continue; + } + // annotations declared on method level, incl. the annotations added via transformers + Collection methodAnnotations = transformedAnnotations.getAnnotations(methodInfo); + if (methodAnnotations.isEmpty()) { + continue; + } + if (Annotations.contains(methodAnnotations, DotNames.OBSERVES)) { + validationErrors.produce(new ValidationErrorBuildItem( + new IllegalStateException(String.format( + "The method %s in the %s class %s declares an observer method but it must be ignored per the CDI rules", + methodInfo.name(), clazz.nestingType().toString(), clazz.name().toString())))); + } else if (Annotations.contains(methodAnnotations, DotNames.PRODUCES)) { + validationErrors.produce(new ValidationErrorBuildItem( + new IllegalStateException(String.format( + "The method %s in the %s class %s declares a producer but it must be ignored per the CDI rules", + methodInfo.name(), clazz.nestingType().toString(), clazz.name().toString())))); + } else if (Annotations.containsAny(methodAnnotations, + interceptorResolverBuildItem.getInterceptorBindings())) { + // detect interceptor bindings declared at nested class methods + validationErrors.produce(new ValidationErrorBuildItem( + new IllegalStateException(String.format( + "The method %s in the %s class %s declares an interceptor binding but it must be ignored per CDI rules", + methodInfo.name(), clazz.nestingType().toString(), clazz.name().toString())))); + } + + } + + // iterate over all fields, check for incorrect producer declarations + for (FieldInfo fieldInfo : clazz.fields()) { + if (Modifier.isStatic(fieldInfo.flags())) { + continue; + } + // annotations declared on field level, incl. the annotations added via transformers + Collection fieldAnnotations = transformedAnnotations.getAnnotations(fieldInfo); + if (fieldAnnotations.isEmpty()) { + continue; + } + if (Annotations.contains(fieldAnnotations, DotNames.PRODUCES)) { + validationErrors.produce(new ValidationErrorBuildItem( + new IllegalStateException(String.format( + "The field %s in the %s class %s declares a producer but it must be ignored per the CDI rules", + fieldInfo.name(), clazz.nestingType().toString(), clazz.name().toString())))); + } + } } } }