[JAVA] Erreur peu claire rencontrée dans le traitement des annotations * Non résolu

J'ai rencontré une erreur que je n'ai pas comprise lorsque j'ai créé mon propre processus d'annotation. Notez le type d'erreur que vous connaissez.

environnement

Java

openjdk 10.0.2

Gradle

Gradle 4.10

Eclipse

4.8.0 (Photon)Pleiades

la mise en oeuvre

Structure des dossiers


|-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-projet de foo, bar --bar implémente le traitement des annotations et foo l'utilise

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");
    }
}

MyInterface.java


package foo;

public interface MyInterface {}

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 à traiter

ConcreteClass.java


package foo;

public class ConcreteClass extends AutoGeneratedClass {}

--Créer ConcreteClass en héritant de ʻAutoGeneratedClass` généré automatiquement par le traitement des annotations

Foo.java


package foo;

@MyAnnotation(clazz=ConcreteClass.class)
public class Foo {}

--Classe qui utilise réellement MyAnnotation --L'élément clazz a une instance Class de ConcreteClass.

Organiser par diagramme de classe

apt.jpg

Événements qui se produisent

La compilation ressemble à ceci:

> gradle :foo:compileJava
> Task :foo:compileJava FAILED
...\foo\src\main\java\foo\ConcreteClass.java:3:Erreur:Impossible de trouver le symbole
public class ConcreteClass extends AutoGeneratedClass {
                                   ^
symbole:Classe AutoGeneratedClass
...\foo\src\main\java\foo\Foo.java:3:Erreur:Type incompatible: Class<ConcreteClass>Classe<? extends MyInterface>Ne peut pas être converti en:
@MyAnnotation(clazz=ConcreteClass.class)
                                 ^
2 erreurs

Essayez différentes choses

Ne se produit pas dans Eclipse

Cela ne se produira pas si vous arrêtez de spécifier la limite supérieure de l'argument de type

MyAnnotation.java


package foo;

...

public @interface MyAnnotation {
-   Class<? extends MyInterface> clazz();
+   Class<?> clazz();
}

--Supprimer la limite supérieure de MyInterface spécifiée dans l'élément clazz de MyAnnotation

Compiler le résultat


> gradle :foo:compileJava
...
BUILD SUCCESSFUL in 3s

Aucune erreur si la limite supérieure est définie sur une classe générée automatiquement

MyAnnotation.java


package foo;

...
public @interface MyAnnotation {
-   Class<? extends MyInterface> clazz();
+   Class<? extends AutoGeneratedClass> clazz();
}

--Change la limite supérieure de clazz de MyInterface à la classe auto-générée ʻAutoGeneratedClass`

Compiler le résultat


> gradle :foo:compileJava
...
BUILD SUCCESSFUL in 3s

--La compilation passera --Mystère

Aucune erreur ne se produit même si la classe générée automatiquement est spécifiée par clazz

Foo.java


package foo;

- @MyAnnotation(clazz=ConcreteClass.class)
+ @MyAnnotation(clazz=AutoGeneratedClass.class)
public class Foo {}

--MyAnnotation a la limite supérieure deClasse <? Etend MyInterface>

Compiler le résultat


...
BUILD SUCCESSFUL in 4s

--Cela compile également --Interface-> Classe auto-générée-> Il semble qu'une erreur se produise lorsqu'elle devient une relation de classe auto-créée

S'appuyer sur ConcreteClass, c'est bien

Foo.java


package foo;

- @MyAnnotation(clazz=ConcreteClass.class)
+ @MyAnnotation
public class Foo {
+   private Class<?> clazz = ConcreteClass.class;
}

Compiler le résultat


> gradle :foo:compileJava
BUILD SUCCESSFUL in 3s

--Compiler les passes --Il semble qu'il n'y ait aucun problème à dépendre de la sous-classe de la classe générée automatiquement.

Il est inutile de s'y référer avec une annotation qui n'est pas la cible du traitement

OtherAnnotation.java


package foo;

...

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface OtherAnnotation {
    Class<? extends MyInterface> clazz();
}

--Créez ʻOtherAnnotation.java avec la même définition que MyAnnotation`

Foo.java


package foo;

- @MyAnnotation(clazz=ConcreteClass.class)
+ @MyAnnotation
+ @OtherAnnotation(clazz=ConcreteClass.class)
public class Foo {}

--Ajout de ʻOtherAnnotation à Foo`

Compiler le résultat


> gradle :foo:compileJava
> Task :foo:compileJava FAILED
...\foo\src\main\java\foo\ConcreteClass.java:3:Erreur:Impossible de trouver le symbole
public class ConcreteClass extends AutoGeneratedClass {
                                   ^
symbole:Classe AutoGeneratedClass
...\foo\src\main\java\foo\Foo.java:4:Erreur:Type incompatible: Class<ConcreteClass>Classe<? extends MyInterface>Ne peut pas être converti en:
@OtherAnnotation(clazz=ConcreteClass.class)
                                    ^
2 erreurs

Vous ne pouvez pas l'écrire dans un endroit qui n'a rien à voir avec le traitement des annotations

OtherClass.java


package foo;

@OtherAnnotation(clazz=ConcreteClass.class)
public class OtherClass {}

Foo.java


package foo;

- @MyAnnotation(clazz=ConcreteClass.class)
+ @MyAnnotation
public class Foo {}

--ʻOtherAnnotation` est le même que le précédent

Compiler le résultat


> Task :foo:compileJava FAILED
...\foo\src\main\java\foo\ConcreteClass.java:3:Erreur:Impossible de trouver le symbole
public class ConcreteClass extends AutoGeneratedClass {
                                   ^
symbole:Classe AutoGeneratedClass
...\foo\src\main\java\foo\OtherClass.java:3:Erreur:Type incompatible: Class<ConcreteClass>Classe<? extends MyInterface>Ne peut pas être converti en:
@OtherAnnotation(clazz=ConcreteClass.class)
                                    ^
2 erreurs

--Même si la classe n'est pas la cible du traitement d'annotation directe, il semble qu'une erreur se produira si ConcreteClass.class est référencé par l'élément d'annotation.

Organiser les symptômes

Si vous organisez les résultats de divers essais, il semble qu'une erreur se produira lorsque les conditions suivantes sont remplies?

--L'instance Class est spécifiée dans l'élément d'annotation. --L'instance Class est une" classe auto-créée "dans la relation hiérarchique de" interface auto-créée-> classe générée automatiquement par le traitement d'annotations-> classe auto-créée ".

Conclusion

Je ne suis pas sûr.

Recommended Posts

Erreur peu claire rencontrée dans le traitement des annotations * Non résolu
Erreur rencontrée lors de l'implémentation de la fonction de balisage
Utiliser MouseListener avec le traitement
Gestion des erreurs avec Graphql-ruby