-
Bug
-
Resolution: Unresolved
-
P4
-
None
-
None
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
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