JDK 13 RFR of JDK-8164819: Make javac's toString() on annotation objects consistent with core reflection
Jonathan Gibbons
jonathan.gibbons at oracle.com
Mon Jun 3 23:01:56 UTC 2019
OK, but with a typo to be fixed in the first file (ArrayBackets)
"It would be nice" if we could share the test cases in the new
AnnotationToStringTest with an equivalent test for javadoc, but I can't
think of a clean way to do that (so far).
-- Jon
On 06/03/2019 01:38 PM, Joe Darcy wrote:
>
> Hello,
>
> Please review the webrev of changes for
>
> JDK-8164819: Make javac's toString() on annotation objects
> consistent with core reflection
> http://cr.openjdk.java.net/~darcy/8164819.2/
>
> Some background, several years ago in JDK 9, the toString output of
> annotations was changed to be usable as the source form of annotations
> (JDK-8162817: "Annotation toString output not reusable for source input").
>
> Separate from the core reflection implementation of annotations, there
> are two other representations of that information available through
> annotation processing in javac from the
> javax.lang.model.AnnotatedConstruct interface, as AnnotationMirror
> objects and as compile-time implementation of annotations in javac.
> (Annotations are implemented as Proxies of the interface of the
> annotation type both at runtime in core reflection and in javac.)
>
> The two intertwined toString implementations of annotation information
> in javac are distinct from the one core reflection and differ in how
> some information is presented. The changes discussed below move the
> javac and core reflection implementations very close to one another by
> making changes in each. The actual code changes are small; the lines
> of test changes are large, but mostly mechanical.
>
> The changes to the javac output are made in:
> src/jdk.compiler/share/classes/com/sun/tools/javac/model/AnnotationProxyMaker.java
>
> The changes to javac's output are:
>
> * The string for of class literals, either stand-alone or in an array
> now properly end in ".class".
> * For an enum constant, just the constant name is emitted rather than
> the full class name followed by the enum constant name. This shorter
> form is also used by javadoc.
>
> The changes to the core reflection output are made in:
> src/java.base/share/classes/sun/reflect/annotation/AnnotationInvocationHandler.java
>
> The changes to core reflection output are:
>
> * Eliding "value=" when it is not necessary, logic already present for
> this in the javac implementations.
> * Changing the formatting of byte values to follow the existing javac
> convention, "(byte)0x1a"
> * Adopting the same quoting policy for char and string values as
> javac. This was accomplished by copying a few small methods from the
> javac internals; I don't think it is worthwhile to go through the
> contortions that would be needed to share this small bit of rarely
> changing code across these modules.
> * Unconditionally append a trailing "L" to long values, as done by javac.
>
> The core reflection changes are directly exercised by updates to:
>
> test/jdk/java/lang/annotation/AnnotationToStringTest.java
>
> A new compile-time test for javac's implementations using (nearly) the
> same test inputs is added as
>
> test/langtools/tools/javac/processing/model/element/AnnotationToStringTest.java
>
> While technically possible, I don't think it would be worth the
> complexity to try to share the javac and core reflection testing
> driven by the same test vectors in a single test file. In particular,
> if changes to one of core reflection and javac altered the annotation
> output, having tests in each area would help flag the change sooner.
>
> The diff of the two flavors of AnnotationToStringTest.java is below
> and shows that the code to extract the annotations values differs
> between the javac and runtime API variants, but that the test vectors
> are the same.
>
> The other test updates, especially in the directly
> test/langtools/tools/javac/processing/model/element/repeatingAnnotations
> are to change the tests for the new output, especially for when
> "value=" it is not needed. I'm still working on the exact updates
> needed for
>
> test/langtools/tools/javac/sym/ElementStructureTest.java
>
> but I wanted to get the remainder of the work out for review.
>
> Thanks,
>
> -Joe
>
> Diff of test files:
>
> diff test/jdk/java/lang/annotation/AnnotationToStringTest.java
> test/langtools/tools/javac/processing/model/element/AnnotationToStringTest.java
> 26c26
> < * @bug 8162817 8168921
> ---
> > * @bug 8164819
> 27a28,30
> > * @library /tools/javac/lib
> > * @build JavacTestingAbstractProcessor AnnotationToStringTest
> > * @compile -processor AnnotationToStringTest -proc:only
> AnnotationToStringTest.java
> 30,31c33,34
> < // See also the sibling compile-time test
> < //
> test/langtools/tools/javac/processing/model/element/AnnotationToStringTest.java
> ---
> > // See also the sibling core reflection test
> > // test/jdk/java/lang/annotation/AnnotationToStringTest.java
> 35a39,42
> > import javax.annotation.processing.*;
> > import javax.lang.model.AnnotatedConstruct;
> > import javax.lang.model.element.*;
> > import javax.lang.model.util.*;
> 40a48,55
> > *
> > * Two flavors of comparison are made:
> > *
> > * 1) Against the AnnotationMirror value from getAnnotationMirrors()
> > *
> > * 2) Against the *Annotation* from getAnnotation(Class<A>)
> > *
> > * These have separate but related implementations.
> 41a57,60
> > public class AnnotationToStringTest extends
> JavacTestingAbstractProcessor {
> > public boolean process(Set<? extends TypeElement> annotations,
> > RoundEnvironment roundEnv) {
> > if (!roundEnv.processingOver()) {
> 43,45c62,93
> < public class AnnotationToStringTest {
> < public static void main(String... args) throws Exception {
> < int failures = 0;
> ---
> > int failures = 0;
> >
> > TypeElement primHostElt =
> >
> Objects.requireNonNull(elements.getTypeElement("AnnotationToStringTest.PrimHost"));
> >
> > List<? extends AnnotationMirror> annotMirrors =
> primHostElt.getAnnotationMirrors();
> >
> > String expectedString =
> primHostElt.getAnnotation(MostlyPrimitive.class).toString();
> >
> > failures += check(expectedString,
> > primHostElt.getAnnotation(ExpectedString.class).value());
> >
> > failures += check(expectedString,
> > retrieveAnnotationMirrorAsString(primHostElt,
> > "MostlyPrimitive"));
> > failures += classyTest();
> > failures += arrayAnnotationTest();
> >
> > if (failures > 0)
> > throw new RuntimeException(failures + " failures");
> > }
> > return true;
> > }
> >
> > /**
> > * Examine annotation mirrors, find the one that matches
> > * annotationName, and return its toString value.
> > */
> > private String
> retrieveAnnotationMirrorAsString(AnnotatedConstruct annotated,
> > String annotationName) {
> > return retrieveAnnotationMirror(annotated,
> annotationName).toString();
> > }
> 47,50c95,106
> < failures +=
> check(PrimHost.class.getAnnotation(ExpectedString.class).value(),
> < PrimHost.class.getAnnotation(MostlyPrimitive.class).toString());
> < failures += classyTest();
> < failures += arrayAnnotationTest();
> ---
> > private String retrieveAnnotationMirrorValue(AnnotatedConstruct
> annotated,
> > String annotationName) {
> > AnnotationMirror annotationMirror =
> > retrieveAnnotationMirror(annotated, annotationName);
> > for (var entry :
> annotationMirror.getElementValues().entrySet()) {
> > if (entry.getKey().getSimpleName().contentEquals("value")) {
> > return entry.getValue().toString();
> > }
> > }
> > throw new RuntimeException("Annotation value() method not
> found: " +
> > annotationMirror.toString());
> > }
> 52,53c108,119
> < if (failures > 0)
> < throw new RuntimeException(failures + " failures");
> ---
> > private AnnotationMirror
> retrieveAnnotationMirror(AnnotatedConstruct annotated,
> > String annotationName) {
> > for (AnnotationMirror annotationMirror :
> annotated.getAnnotationMirrors()) {
> > System.out.println(annotationMirror.getAnnotationType());
> > if (annotationMirror
> > .getAnnotationType()
> > .toString()
> > .equals(annotationName) ) {
> > return annotationMirror;
> > }
> > }
> > throw new RuntimeException("Annotation " + annotationName +
> " not found.");
> 104c170
> < private static int classyTest() {
> ---
> > private int classyTest() {
> 106c172,177
> < for (Field f : AnnotationHost.class.getFields()) {
> ---
> >
> > TypeElement annotationHostElt =
> >
> Objects.requireNonNull(elements.getTypeElement("AnnotationToStringTest.AnnotationHost"));
> >
> > for (VariableElement f :
> ElementFilter.fieldsIn(annotationHostElt.getEnclosedElements())) {
> > String expected =
> f.getAnnotation(ExpectedString.class).value();
> 107a179
> >
> 109,110c181,184
> < failures +=
> check(f.getAnnotation(ExpectedString.class).value(),
> < a.toString());
> ---
> > failures += check(expected, a.toString());
> >
> > failures += check(expected,
> > retrieveAnnotationMirrorAsString(f, "Classy") );
> 151c225
> < private static int arrayAnnotationTest() {
> ---
> > private int arrayAnnotationTest() {
> 153,157c227,251
> < for (Field f : ArrayAnnotationHost.class.getFields()) {
> < Annotation[] annotations = f.getAnnotations();
> < System.out.println(annotations[1]);
> < failures += check(((ExpectedString)annotations[0]).value(),
> < annotations[1].toString());
> ---
> >
> > TypeElement arrayAnnotationHostElt =
> > Objects.requireNonNull(elements
> > .getTypeElement("AnnotationToStringTest.ArrayAnnotationHost"));
> >
> > for (VariableElement f :
> > ElementFilter.fieldsIn(arrayAnnotationHostElt.getEnclosedElements())) {
> > var annotations = f.getAnnotationMirrors();
> > // String expected = retrieveAnnotationMirrorValue(f,
> "ExpectedString");
> > String expected =
> f.getAnnotation(ExpectedString.class).value();
> >
> > // Problem with
> > // Need a de-quote method...
> > // expected = expected.substring(1, expected.length() - 1);
> >
> > failures +=
> > check(expected,
> > annotations.get(1).toString());
> >
> > // Get the array-valued annotation as an annotation
> > failures +=
> > check(expected,
> > retrieveAnnotationMirrorAsString(f,
> > annotations.get(1)
> > .getAnnotationType().toString()));
> 176a271
> >
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20190603/6377dc74/attachment-0001.html>
More information about the compiler-dev
mailing list