[JAVA] When running annotation processing in the IDE, the annotation information whose Retention is SOURCE may not be obtained.

When running annotation processing in the IDE, the annotation information defined by @Retention (RetentionPolicy.SOURCE) may not be obtained under certain conditions.

environment

OS

Windows 10

Java

openjdk 10.0.2

Eclipse

Photon (4.8.0)Pleiades

IntelliJ

IntelliJ IDEA 2018.2.3 (Community Edition)

Gradle

Gradle 4.10

Symptoms

Source code

Project structure


|-foo/
| `-src/main/java/
|   `-sample/foo/
|     |-Fizz.java
|     `-Buzz.java
|
|-bar/
| |-src/main/java/
| | `-sample/bar/
| |   |-MyRuntimeRetention.java
| |   |-MyClassRetention.java
| |   |-MySourceRetention.java
| |   `-MyProcessor.java
| |
| `-src/main/resources/
|   `-META-INF/services
|     `-javax.annotation.processing.Processor
|
|-build.gradle
`-settings.gradle

--Multi-project of foo, bar --The project where bar implements annotation processing --foo is a project that uses bar annotation processing --MyRuntimeRetention.java, MyClassRetention.java, MySourceRetention.java set the value corresponding to the name in Retention in their own annotations.

MyRuntimeRetention.java


package sample.bar;

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 MyRuntimeRetention {
}

MyClassRetention.java


package sample.bar;

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.CLASS)
public @interface MyClassRetention {
}

MySourceRetention.java


package sample.bar;

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.SOURCE)
public @interface MySourceRetention {
}

--Class in which MyProcessor.java implements annotation processing

MyProcessor.java


package sample.bar;

import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Messager;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
import javax.tools.Diagnostic.Kind;

public class MyProcessor extends AbstractProcessor {

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        Elements elements = this.processingEnv.getElementUtils();
        
        if (!annotations.isEmpty()) {
            this.printAnnotations(elements.getTypeElement("sample.foo.Fizz"));
            this.printAnnotations(elements.getTypeElement("sample.foo.Buzz"));
        }
        
        return true;
    }
    
    private void printAnnotations(TypeElement element) {
        element.getAnnotationMirrors().forEach(annotation -> {
            this.processingEnv.getMessager().printMessage(Kind.NOTE, element.getSimpleName() + " : " + annotation);
        });
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.RELEASE_10;
    }
    
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        return Set.of(MySourceRetention.class.getCanonicalName());
    }
}

--Getting the TypeElement of the Fizz, Buzz class and outputting the annotations set in the class in a list.

Fizz.java


package sample.foo;

import sample.bar.MyClassRetention;
import sample.bar.MyRuntimeRetention;
import sample.bar.MySourceRetention;

@MyRuntimeRetention
@MyClassRetention
@MySourceRetention
public class Fizz {
}

Buzz.java


package sample.foo;

import sample.bar.MyClassRetention;
import sample.bar.MyRuntimeRetention;
import sample.bar.MySourceRetention;

@MyRuntimeRetention
@MyClassRetention
@MySourceRetention
public class Buzz {
}

--The foo project Fizz, Buzz sets three self-made annotations in the class.

Processing to be performed

In this state, modify only the ** Fizz class and execute ** compilation. Then, the result will be different when running in Gradle and when running in IDE (Eclipse, IntelliJ).

When running on Gradle

> gradle :foo:compileJava

Caution:Fizz : @sample.bar.MyRuntimeRetention
Caution:Fizz : @sample.bar.MyClassRetention
Caution:Fizz : @sample.bar.MySourceRetention
Caution:Buzz : @sample.bar.MyRuntimeRetention
Caution:Buzz : @sample.bar.MyClassRetention
Caution:Buzz : @sample.bar.MySourceRetention

--You can get the information of all annotations normally.

When running in Eclipse

apt.jpg

--All annotations of Fizz class have been acquired --However, @MySourceRetention cannot get the annotation of the Buzz class.

When running on IntelliJ

apt.jpg

--This is also the same as Eclipse, and @MySourceRetention cannot be obtained from the annotation information of the Buzz class.

You can also get it in the IDE by modifying Buzz

--Modify not only the Fizz class but also the Buzz class and then run the build to run the annotation process. --Then, the result is as follows.

Eclipse apt.jpg

--You can also get the @MySourceRetention set in Buzz.

IntelliJ apt.jpg

--The same is true here, and you can get @MySourceRetention.

Guess what happened

--When Retention is set to SOURCE, annotation information does not remain in the class file /RetentionPolicy.html#SOURCE) --In view of the fact that only the information of the specified annotation could not be obtained if it was not modified, probably if the annotation processing works in the IDE (Eclipse, IntelliJ), the class without modification I feel that the information is based on the previous compilation result (class file). --By the way, I haven't tried NetBeans

Conclusion (guess)

--When annotation processing works in IDE (Eclipse, IntelliJ), it seems that you cannot get the annotation information of Retention set to SOURCE in the class without modification. --The reason is probably that the IDE seems to get the information of the unmodified class from the previous compilation result (class file). --When writing annotation processing by yourself, be careful when handling annotations with Retention of SOURCE. --If you are making your own annotations, it is a good idea to set Retention to CLASS or higher.

Recommended Posts

When running annotation processing in the IDE, the annotation information whose Retention is SOURCE may not be obtained.
When the project is not displayed in eclipse
Processing when an ID that does not exist in the database is entered in the URL
How to set when "The constructor Empty () is not visible" occurs in junit
When I run the source command in the Ubuntu Makefile, it says "source: command not found"