8005295: Use mandated information for printing of repeating annotations

Reviewed-by: jjg
This commit is contained in:
Joe Darcy 2021-04-09 22:02:34 +00:00
parent f26cd2ac1c
commit 863feab998
3 changed files with 181 additions and 2 deletions

View File

@ -522,10 +522,83 @@ public class PrintingProcessor extends AbstractProcessor {
private void printAnnotations(Element e) {
List<? extends AnnotationMirror> annots = e.getAnnotationMirrors();
for(AnnotationMirror annotationMirror : annots) {
// Handle compiler-generated container annotations specially
if (!printedContainerAnnotation(e, annotationMirror)) {
indent();
writer.println(annotationMirror);
}
}
}
private boolean printedContainerAnnotation(Element e,
AnnotationMirror annotationMirror) {
/*
* If the annotation mirror is marked as mandated and
* looks like a container annotation, elide printing the
* container and just print the wrapped contents.
*/
if (elementUtils.getOrigin(e, annotationMirror) == Elements.Origin.MANDATED) {
// From JLS Chapter 9, an annotation interface AC is a
// containing annotation interface of A if AC declares
// a value() method whose return type is A[] and any
// methods declared by AC other than value() have a
// default value. As an implementation choice, if more
// than one annotation element is found on the outer
// annotation, in other words, something besides a
// "value" method, the annotation will not be treated
// as a wrapper for the purposes of printing. These
// checks are intended to preserve correctness in the
// face of some other kind of annotation being marked
// as mandated.
var entries = annotationMirror.getElementValues().entrySet();
if (entries.size() == 1) {
var annotationType = annotationMirror.getAnnotationType();
var annotationTypeAsElement = annotationType.asElement();
var entry = entries.iterator().next();
var annotationElements = entry.getValue();
// Check that the annotation type declaration has
// a single method named "value" and that it
// returns an array. A stricter check would be
// that it is an array of an annotation type and
// that annotation type in turn was repeatable.
if (annotationTypeAsElement.getKind() == ElementKind.ANNOTATION_TYPE) {
var annotationMethods =
ElementFilter.methodsIn(annotationTypeAsElement.getEnclosedElements());
if (annotationMethods.size() == 1) {
var valueMethod = annotationMethods.get(0);
var returnType = valueMethod.getReturnType();
if ("value".equals(valueMethod.getSimpleName().toString()) &&
returnType.getKind() == TypeKind.ARRAY) {
// Use annotation value visitor that
// returns a boolean if it prints out
// contained annotations as expected
// and false otherwise
return (new SimpleAnnotationValueVisitor14<Boolean, Void>(false) {
@Override
public Boolean visitArray(List<? extends AnnotationValue> vals, Void p) {
if (vals.size() < 2) {
return false;
} else {
for (var annotValue: vals) {
indent();
writer.println(annotValue.toString());
}
return true;
}
}
}).visit(annotationElements);
}
}
}
}
}
return false;
}
// TODO: Refactor
private void printParameters(ExecutableElement e) {

View File

@ -0,0 +1,66 @@
/*
* Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8005295
* @summary Verify repeating annotations are printed as expected
* @compile/ref=XprintRepeatingAnnotations.out -Xprint XprintRepeatingAnnotations.java
*/
import java.lang.annotation.*;
import static java.lang.annotation.RetentionPolicy.*;
@Foo(1)
@Foo(2)
@Bar(3)
@Bar(4)
public class XprintRepeatingAnnotations {
}
@Retention(RUNTIME)
@Documented
@Repeatable(Foos.class)
@interface Foo {
int value();
}
@Retention(RUNTIME)
@Documented
@interface Foos {
Foo[] value();
}
@Retention(RUNTIME)
@Documented
@Repeatable(Bars.class)
@interface Bar {
int value();
}
@Retention(RUNTIME)
@Documented
@interface Bars {
Bar[] value();
int quux() default 1;
}

View File

@ -0,0 +1,40 @@
@Foo(1)
@Foo(2)
@Bars({@Bar(3), @Bar(4)})
public class XprintRepeatingAnnotations {
public XprintRepeatingAnnotations();
}
@java.lang.annotation.Retention(RUNTIME)
@java.lang.annotation.Documented
@java.lang.annotation.Repeatable(Foos.class)
@interface Foo {
int value();
}
@java.lang.annotation.Retention(RUNTIME)
@java.lang.annotation.Documented
@interface Foos {
Foo[] value();
}
@java.lang.annotation.Retention(RUNTIME)
@java.lang.annotation.Documented
@java.lang.annotation.Repeatable(Bars.class)
@interface Bar {
int value();
}
@java.lang.annotation.Retention(RUNTIME)
@java.lang.annotation.Documented
@interface Bars {
Bar[] value();
int quux() default 1;
}