From 5d3a353c1b0cc92b15c41ae8d1f7f08ac9d7d4f3 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 | 73 ++++++++++++++----- 1 file changed, 53 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..5bbd2bdfcc330 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 @@ -13,7 +13,9 @@ 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 +74,66 @@ 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 + Collection classLevelAnnotations = transformedAnnotations.getAnnotations(clazz); + 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 + // note that since JDK 16, you can have static method inside inner non-static class + for (MethodInfo methodInfo : clazz.methods()) { + // 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) + || Annotations.contains(methodAnnotations, DotNames.OBSERVES_ASYNC)) { + 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 (!Modifier.isStatic(methodInfo.flags()) && 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()) { + // 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())))); + } + } } } }