Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8194900

Inconsistent handling of recoverable errors during annotation processing

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: P4 P4
    • None
    • None
    • tools

      The following example contains a simple class hierarchy where A extends B, and B extends C. B is generated by an annotation processor.

      Using `@I(B.class)` in the compilation succeeds: a recoverable 'cant.resolve' error is reported, and fixed when B is generated during the first annotation processing round.

      Using `@I(A.class)` does not succeed: checking the constraint on I.value requires A's super type, which hasn't been generated yet, resulting in a non-recoverable inconvertible.types error.

      This is potentially surprising, since in both cases the annotation depends on the missing type, and the example that compiles depends more directly on the missing type.

      Is this working as intended?

      === P.java
      import static java.nio.charset.StandardCharsets.UTF_8;

      import java.io.IOError;
      import java.io.IOException;
      import java.io.OutputStream;
      import java.util.Set;
      import javax.annotation.processing.AbstractProcessor;
      import javax.annotation.processing.RoundEnvironment;
      import javax.annotation.processing.SupportedAnnotationTypes;
      import javax.lang.model.SourceVersion;
      import javax.lang.model.element.TypeElement;

      @SupportedAnnotationTypes("*")
      public final class P extends AbstractProcessor {

        @Override
        public SourceVersion getSupportedSourceVersion() {
          return SourceVersion.latestSupported();
        }

        boolean first = true;

        @Override
        public final boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
          if (first) {
            try (OutputStream os = processingEnv.getFiler().createSourceFile("B").openOutputStream()) {
              os.write("class B extends C {}".getBytes(UTF_8));
            } catch (IOException e) {
              throw new IOError(e);
            }
            first = false;
          }
          return true;
        }
      }
      === T.java
      @interface I {
        Class<? extends C> value() default C.class;
      }

      class C {}

      // generated:
      // class B extends C {}

      class A extends B {}

      // @I(B.class) // OK
      @I(A.class) // error: incompatible types: Class<A> cannot be converted to Class<? extends C>
      class T {}
      ===

      $ javac -fullversion -processor P T.java
      javac full version "9.0.1+11"
      T.java:10: error: cannot find symbol
      class A extends B {}
                      ^
        symbol: class B
      T.java:13: error: incompatible types: Class<A> cannot be converted to Class<? extends C>
      @I(A.class) // error: incompatible types: Class<A> cannot be converted to Class<? extends C>
          ^
      2 errors

            Unassigned Unassigned
            cushon Liam Miller-Cushon
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated: