I ran into an error I didn't understand when I made my own annotation process. Make a note of what kind of error you know.
Java
openjdk 10.0.2
Gradle
Gradle 4.10
Eclipse
4.8.0 (Photon)
※Pleiades
Folder structure
|-settings.gradle
|-build.gradle
|-foo/
| `-src/main/java/
| `-foo/
| |-Foo.java
| |-ConcreteClass.java
| |-MyAnnotation.java
| `-MyInterface.java
|
`-bar/
`src/main/
|-java/
| `-bar/
| `-MyProcessor.java
`-resources/
`-META-INF/services/
`-javax.annotation.processing.Processor
--Multi-project of foo
, bar
--bar
implements annotation processing and foo
uses it
MyProcessor.java
package bar;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.TypeElement;
import javax.tools.JavaFileObject;
public class MyProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (!annotations.isEmpty()) {
try {
JavaFileObject javaFileObject = this.processingEnv.getFiler().createSourceFile("foo.AutoGeneratedClass");
try (BufferedWriter writer = new BufferedWriter(javaFileObject.openWriter())) {
writer.write(
"package foo;\n" +
"import foo.MyInterface;\n" +
"public class AutoGeneratedClass implements MyInterface {}"
);
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
return true;
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latest();
}
@Override
public Set<String> getSupportedAnnotationTypes() {
return Set.of("foo.MyAnnotation");
}
}
--Implemented annotation processing for MyAnnotation
annotations
--A class called ʻAutoGeneratedClass that implements the
MyInterface` interface is automatically generated.
MyInterface.java
package foo;
public interface MyInterface {}
--Just an interface
MyAnnotation.java
package foo;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
Class<? extends MyInterface> clazz();
}
--Annotation to be processed
--The clazz
element accepts Class
instances up to MyInterface
ConcreteClass.java
package foo;
public class ConcreteClass extends AutoGeneratedClass {}
--Create ConcreteClass
by inheriting ʻAutoGeneratedClass` automatically generated by annotation processing
Foo.java
package foo;
@MyAnnotation(clazz=ConcreteClass.class)
public class Foo {}
--Class that actually uses MyAnnotation
--The clazz
element has a Class
instance of ConcreteClass
.
Compiling this looks like this:
> gradle :foo:compileJava
> Task :foo:compileJava FAILED
...\foo\src\main\java\foo\ConcreteClass.java:3:error:Can't find symbol
public class ConcreteClass extends AutoGeneratedClass {
^
symbol:Class AutoGeneratedClass
...\foo\src\main\java\foo\Foo.java:3:error:Incompatible type: Class<ConcreteClass>Class<? extends MyInterface>Cannot be converted to:
@MyAnnotation(clazz=ConcreteClass.class)
^
2 errors
--Failed to compile ConcreteClass
because ʻAutoGeneratedClass`, which should be automatically generated, cannot be found.
--If you import this project into Eclipse as it is and perform annotation processing, no error will occur for some reason.
--I tried compiling with only the plain javac
command without using Gradle, but an error still occurred.
MyAnnotation.java
package foo;
...
public @interface MyAnnotation {
- Class<? extends MyInterface> clazz();
+ Class<?> clazz();
}
--Remove the upper limit of MyInterface
specified in the clazz
element of MyAnnotation
Compile result
> gradle :foo:compileJava
...
BUILD SUCCESSFUL in 3s
--Then, the compilation will pass. --Mystery
MyAnnotation.java
package foo;
...
public @interface MyAnnotation {
- Class<? extends MyInterface> clazz();
+ Class<? extends AutoGeneratedClass> clazz();
}
--Change the upper limit of clazz
from MyInterface
to the auto-generated class ʻAutoGeneratedClass`
Compile result
> gradle :foo:compileJava
...
BUILD SUCCESSFUL in 3s
--Compile will pass --Mystery
Foo.java
package foo;
- @MyAnnotation(clazz=ConcreteClass.class)
+ @MyAnnotation(clazz=AutoGeneratedClass.class)
public class Foo {}
--MyAnnotation
has the upper limit ofClass <? Extends MyInterface>
Compile result
...
BUILD SUCCESSFUL in 4s
--This also compiles --Interface-> Auto-generated class-> It seems that an error occurs when it becomes a relationship of self-made class
Foo.java
package foo;
- @MyAnnotation(clazz=ConcreteClass.class)
+ @MyAnnotation
public class Foo {
+ private Class<?> clazz = ConcreteClass.class;
}
--Removed the clazz
element of MyAnnotation
--Use ConcreteClass
in the field
--See also ConcreteClass.class
Compile result
> gradle :foo:compileJava
BUILD SUCCESSFUL in 3s
--Compile passes --It seems that there is no problem in depending on the subclass of the automatically generated class.
OtherAnnotation.java
package foo;
...
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface OtherAnnotation {
Class<? extends MyInterface> clazz();
}
--Create ʻOtherAnnotation.java with the same definition as
MyAnnotation`
Foo.java
package foo;
- @MyAnnotation(clazz=ConcreteClass.class)
+ @MyAnnotation
+ @OtherAnnotation(clazz=ConcreteClass.class)
public class Foo {}
--Added ʻOtherAnnotation to
Foo --The
clazz element towards
MyAnnotation` has been removed
Compile result
> gradle :foo:compileJava
> Task :foo:compileJava FAILED
...\foo\src\main\java\foo\ConcreteClass.java:3:error:Can't find symbol
public class ConcreteClass extends AutoGeneratedClass {
^
symbol:Class AutoGeneratedClass
...\foo\src\main\java\foo\Foo.java:4:error:Incompatible type: Class<ConcreteClass>Class<? extends MyInterface>Cannot be converted to:
@OtherAnnotation(clazz=ConcreteClass.class)
^
2 errors
--The same error as for MyAnnotation
--It seems that it doesn't matter whether the annotation is the target of annotation processing.
OtherClass.java
package foo;
@OtherAnnotation(clazz=ConcreteClass.class)
public class OtherClass {}
Foo.java
package foo;
- @MyAnnotation(clazz=ConcreteClass.class)
+ @MyAnnotation
public class Foo {}
--ʻOtherAnnotationis the same as the previous one --You are using
@OtherAnnotation (clazz = ConcreteClass.class) in ʻOtherClass
, which has nothing to do with annotation processing.
Compile result
> Task :foo:compileJava FAILED
...\foo\src\main\java\foo\ConcreteClass.java:3:error:Can't find symbol
public class ConcreteClass extends AutoGeneratedClass {
^
symbol:Class AutoGeneratedClass
...\foo\src\main\java\foo\OtherClass.java:3:error:Incompatible type: Class<ConcreteClass>Class<? extends MyInterface>Cannot be converted to:
@OtherAnnotation(clazz=ConcreteClass.class)
^
2 errors
--It seems that an error will occur if ConcreteClass.class
is referenced by an annotation element even if it is not a class that is directly subject to annotation processing.
If you organize the results of various trials, it seems that an error will occur when the following conditions are met?
--The Class
instance is specified in the annotation element.
--The Class
instance is a" self-made class "in the hierarchical relationship of" self-made interface-> class automatically generated by annotation processing-> self-made class ".
--The definition of the element that receives the Class
instance on the annotation side isClass <? Extends self-made interface>
.
--Executed by OpenJDK annotation processing
I'm not sure.