Skip to content
This repository has been archived by the owner on Oct 10, 2024. It is now read-only.

Getting a CodeBlock from an AnnotationValue for an enum constant #845

Open
cushon opened this issue Jun 9, 2021 · 2 comments
Open

Getting a CodeBlock from an AnnotationValue for an enum constant #845

cushon opened this issue Jun 9, 2021 · 2 comments

Comments

@cushon
Copy link

cushon commented Jun 9, 2021

JDK-8164819 changed the toString() implementation of some AnnotationValue implementations to match core reflection.

For AnnotationValues representing an enum constant, the toString() is now the simple name instead of a fully qualified name. I encountered some code that using CodeBlock.of("$L", annotationValue), which ends up just calling toString(), which now results in an unqualified simple name of the enum constant.

Is there already a better way to convert an AnnotationValue to a CodeBlock? I couldn't find one. There's some logic in AnnotationSpec that's close to what I want, but the only entry point takes an entire AnnotationMirror:

@Override public Builder visitEnumConstant(VariableElement c, String name) {
return builder.addMember(name, "$T.$L", c.asType(), c.getSimpleName());
}

Demo:

import com.squareup.javapoet.CodeBlock;
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.AnnotationValue;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind;

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

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

  enum E {
    ONE;
  }

  @interface A {

    E value() default E.ONE;
  }

  @Override
  public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
    TypeElement typeElement = processingEnv.getElementUtils()
        .getTypeElement("P.A");
    for (Element member : typeElement.getEnclosedElements()) {
      if (member.getSimpleName().contentEquals("value")) {
        AnnotationValue av = ((ExecutableElement) member).getDefaultValue();
        processingEnv.getMessager().printMessage(Kind.NOTE, CodeBlock.of("$L", av).toString());
      }
    }
    return false;
  }
}

With JDK 11, CodeBlock.of("$L", av) is the qualified name P.E.ONE:

$ javac -version  -processorpath .:javapoet-1.13.0.jar -processor P -cp javapoet-1.13.0.jar P.java
javac 11.0.11
Note: P.E.ONE
Note: P.E.ONE

With JDK 17, it's just ONE:

$ javac -version  -processorpath .:javapoet-1.13.0.jar -processor P -cp javapoet-1.13.0.jar P.java
javac 17-ea
Note: ONE
Note: ONE
@cushon
Copy link
Author

cushon commented Jun 15, 2021

A few updates

  • I ran into this in some more processors, and the incompatible change in javac is now being tracked by JDK-8268729
  • I'm looking at adding a helpers to auto-common to convert AnnotationValue to a more useful string
  • It might still be nice to have support in JavaPoet for converting AnnotationValues into source

@skystar1191
Copy link

I'm working on this issue and will try to fix it.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants