--- a/jdk/test/java/lang/annotation/AnnotationVerifier.java Wed Jan 25 14:10:03 2017 +0000
+++ b/jdk/test/java/lang/annotation/AnnotationVerifier.java Wed Jan 25 15:53:17 2017 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, 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
@@ -27,9 +27,15 @@
* Create class file using ASM, slightly modified the ASMifier output
*/
-import sun.reflect.annotation.AnnotationType;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.lang.annotation.Annotation;
import java.lang.annotation.AnnotationFormatError;
-import org.testng.annotations.*;
+import java.util.Arrays;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
/*
* @test
@@ -37,27 +43,380 @@
* @summary Verify valid annotation
* @modules java.base/jdk.internal.org.objectweb.asm
* @modules java.base/sun.reflect.annotation
- * @clean AnnotationWithVoidReturn.class AnnotationWithParameter.class
- * @compile -XDignore.symbol.file ClassFileGenerator.java
+ * @clean AnnotationWithVoidReturn AnnotationWithParameter
+ * AnnotationWithExtraInterface AnnotationWithException
+ * AnnotationWithHashCode AnnotationWithDefaultMember
+ * AnnotationWithoutAnnotationAccessModifier HolderX
+ * @compile -XDignore.symbol.file ClassFileGenerator.java GoodAnnotation.java
* @run main ClassFileGenerator
* @run testng AnnotationVerifier
*/
public class AnnotationVerifier {
+ //=======================================================
+ // GoodAnnotation...
+
+ @GoodAnnotation
+ static class HolderA {
+ }
+
+ @Test
+ public void holderA_goodAnnotation() {
+ testGetAnnotation(HolderA.class, GoodAnnotation.class, true);
+ }
+
+ @Test
+ public void holderA_annotations() {
+ testGetAnnotations(HolderA.class, GoodAnnotation.class);
+ }
+
+ //=======================================================
+ // AnnotationWithParameter...
+
+ /*
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface AnnotationWithParameter {
+ int m(int x) default -1;
+ }
+ */
+
+ @GoodAnnotation
@AnnotationWithParameter
+ static class HolderB {
+ }
+
+ @Test
+ public void holderB_annotationWithParameter() {
+ testGetAnnotation(HolderB.class, AnnotationWithParameter.class, false);
+ }
+
+ @Test
+ public void holderB_goodAnnotation() {
+ testGetAnnotation(HolderB.class, GoodAnnotation.class, true);
+ }
+
+ @Test
+ public void holderB_annotations() {
+ testGetAnnotations(HolderB.class, GoodAnnotation.class);
+ }
+
+ //=======================================================
+ // AnnotationWithVoidReturn...
+
+ /*
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface AnnotationWithVoidReturn {
+ void m() default 1;
+ }
+ */
+
+ @GoodAnnotation
@AnnotationWithVoidReturn
- static class BadAnnotation {
+ static class HolderC {
+ }
+
+ @Test(expectedExceptions = AnnotationFormatError.class)
+ public void holderC_annotationWithVoidReturn() {
+ testGetAnnotation(HolderC.class, AnnotationWithVoidReturn.class, false);
+ }
+
+ @Test(expectedExceptions = AnnotationFormatError.class)
+ public void holderC_goodAnnotation() {
+ testGetAnnotation(HolderC.class, GoodAnnotation.class, false);
+ }
+
+ @Test(expectedExceptions = AnnotationFormatError.class)
+ public void holderC_annotations() {
+ testGetAnnotations(HolderC.class);
+ }
+
+ //=======================================================
+ // AnnotationWithExtraInterface...
+
+ /*
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface AnnotationWithExtraInterface extends java.io.Serializable {
+ int m() default 1;
+ }
+ */
+
+ @GoodAnnotation
+ @AnnotationWithExtraInterface
+ static class HolderD {
+ }
+
+ @Test(expectedExceptions = AnnotationFormatError.class)
+ public void holderD_annotationWithExtraInterface() {
+ testGetAnnotation(HolderD.class, AnnotationWithExtraInterface.class, false);
+ }
+
+ @Test(expectedExceptions = AnnotationFormatError.class)
+ public void holderD_goodAnnotation() {
+ testGetAnnotation(HolderD.class, GoodAnnotation.class, false);
+ }
+
+ @Test(expectedExceptions = AnnotationFormatError.class)
+ public void holderD_annotations() {
+ testGetAnnotations(HolderD.class);
+ }
+
+ //=======================================================
+ // AnnotationWithException...
+
+ /*
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface AnnotationWithException {
+ int m() throws Exception default 1;
+ }
+ */
+
+ @GoodAnnotation
+ @AnnotationWithException
+ static class HolderE {
+ }
+
+ @AnnotationWithException
+ static class HolderE2 {
+ }
+
+ @Test
+ public void holderE_annotationWithException() {
+ testGetAnnotation(HolderE.class, AnnotationWithException.class, true);
+ }
+
+ @Test
+ public void holderE_goodAnnotation() {
+ testGetAnnotation(HolderE.class, GoodAnnotation.class, true);
+ }
+
+ @Test
+ public void holderE_annotations() {
+ testGetAnnotations(HolderE.class, GoodAnnotation.class, AnnotationWithException.class);
+ }
+
+ @Test(expectedExceptions = AnnotationFormatError.class)
+ public void holderE_annotationWithException_equals() {
+ AnnotationWithException ann1, ann2;
+ try {
+ ann1 = HolderE.class.getAnnotation(AnnotationWithException.class);
+ ann2 = HolderE2.class.getAnnotation(AnnotationWithException.class);
+ } catch (Throwable t) {
+ throw new AssertionError("Unexpected exception", t);
+ }
+ Assert.assertNotNull(ann1);
+ Assert.assertNotNull(ann2);
+
+ testEquals(ann1, ann2, true); // this throws AnnotationFormatError
+ }
+
+ //=======================================================
+ // AnnotationWithHashCode...
+
+ /*
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface AnnotationWithHashCode {
+ int hashCode() default 1;
+ }
+ */
+
+ @GoodAnnotation
+ @AnnotationWithHashCode
+ static class HolderF {
+ }
+
+ @AnnotationWithHashCode
+ static class HolderF2 {
+ }
+
+ @Test
+ public void holderF_annotationWithHashCode() {
+ testGetAnnotation(HolderF.class, AnnotationWithHashCode.class, true);
}
@Test
- @ExpectedExceptions(IllegalArgumentException.class)
- public void annotationValidationIAE() {
- AnnotationType.getInstance(AnnotationWithParameter.class);
+ public void holderF_goodAnnotation() {
+ testGetAnnotation(HolderF.class, GoodAnnotation.class, true);
+ }
+
+ @Test
+ public void holderF_annotations() {
+ testGetAnnotations(HolderF.class, GoodAnnotation.class, AnnotationWithHashCode.class);
+ }
+
+ @Test(expectedExceptions = AnnotationFormatError.class)
+ public void holderF_annotationWithHashCode_equals() {
+ AnnotationWithHashCode ann1, ann2;
+ try {
+ ann1 = HolderF.class.getAnnotation(AnnotationWithHashCode.class);
+ ann2 = HolderF2.class.getAnnotation(AnnotationWithHashCode.class);
+ } catch (Throwable t) {
+ throw new AssertionError("Unexpected exception", t);
+ }
+ Assert.assertNotNull(ann1);
+ Assert.assertNotNull(ann2);
+
+ testEquals(ann1, ann2, true); // this throws AnnotationFormatError
+ }
+
+ //=======================================================
+ // AnnotationWithDefaultMember...
+
+ /*
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface AnnotationWithDefaultMember {
+ int m() default 1;
+ default int d() default 2 { return 2; }
+ }
+ */
+
+ @GoodAnnotation
+ @AnnotationWithDefaultMember
+ static class HolderG {
+ }
+
+ @AnnotationWithDefaultMember
+ static class HolderG2 {
+ }
+
+ @Test
+ public void holderG_annotationWithDefaultMember() {
+ testGetAnnotation(HolderG.class, AnnotationWithDefaultMember.class, true);
+ }
+
+ @Test
+ public void holderG_goodAnnotation() {
+ testGetAnnotation(HolderG.class, GoodAnnotation.class, true);
+ }
+
+ @Test
+ public void holderG_annotations() {
+ testGetAnnotations(HolderG.class, GoodAnnotation.class, AnnotationWithDefaultMember.class);
}
@Test(expectedExceptions = AnnotationFormatError.class)
- public void annotationValidationAFE() {
- BadAnnotation.class.getAnnotation(AnnotationWithVoidReturn.class);
+ public void holderG_annotationWithDefaultMember_equals() {
+ AnnotationWithDefaultMember ann1, ann2;
+ try {
+ ann1 = HolderG.class.getAnnotation(AnnotationWithDefaultMember.class);
+ ann2 = HolderG2.class.getAnnotation(AnnotationWithDefaultMember.class);
+ } catch (Throwable t) {
+ throw new AssertionError("Unexpected exception", t);
+ }
+ Assert.assertNotNull(ann1);
+ Assert.assertNotNull(ann2);
+
+ testEquals(ann1, ann2, true); // this throws AnnotationFormatError
+ }
+
+ //=======================================================
+ // AnnotationWithoutAnnotationAccessModifier...
+
+ /*
+
+ @Retention(RetentionPolicy.RUNTIME)
+ public interface AnnotationWithoutAnnotationAccessModifier extends Annotation {
+ int m() default 1;
+ }
+
+ @GoodAnnotation
+ @AnnotationWithoutAnnotationAccessModifier
+ static class HolderX {
+ }
+
+ */
+
+ @Test
+ public void holderX_annotationWithoutAnnotationAccessModifier() {
+ testGetAnnotation(HolderX.class, AnnotationWithoutAnnotationAccessModifier.class, false);
+ }
+
+ @Test
+ public void holderX_goodAnnotation() {
+ testGetAnnotation(HolderX.class, GoodAnnotation.class, true);
+ }
+
+ @Test
+ public void holderX_annotations() {
+ testGetAnnotations(HolderX.class, GoodAnnotation.class);
+ }
+
+ //=======================================================
+ // utils
+ //
+
+ private static void testGetAnnotation(Class<?> holderClass,
+ Class<? extends Annotation> annType,
+ boolean expectedPresent) {
+ Object result = null;
+ try {
+ try {
+ result = holderClass.getAnnotation(annType);
+ if (expectedPresent != (result != null)) {
+ throw new AssertionError("Expected " +
+ (expectedPresent ? "non-null" : "null") +
+ " result, but got: " + result);
+ }
+ } catch (Throwable t) {
+ result = t;
+ throw t;
+ }
+ } finally {
+ System.out.println("\n" +
+ holderClass.getSimpleName() +
+ ".class.getAnnotation(" +
+ annType.getSimpleName() +
+ ".class) = " +
+ result);
+ }
+ }
+
+ private static void testGetAnnotations(Class<?> holderClass,
+ Class<? extends Annotation> ... expectedTypes) {
+ Object result = null;
+ try {
+ try {
+ Annotation[] anns = holderClass.getAnnotations();
+
+ Set<Class<? extends Annotation>> gotTypes =
+ Stream.of(anns)
+ .map(Annotation::annotationType)
+ .collect(Collectors.toSet());
+
+ Set<Class<? extends Annotation>> expTypes =
+ Stream.of(expectedTypes)
+ .collect(Collectors.toSet());
+
+ if (!expTypes.equals(gotTypes)) {
+ throw new AssertionError("Expected annotation types: " + expTypes +
+ " but got: " + Arrays.toString(anns));
+ }
+ result = Arrays.toString(anns);
+ } catch (Throwable t) {
+ result = t;
+ throw t;
+ }
+ } finally {
+ System.out.println("\n" +
+ holderClass.getSimpleName() +
+ ".class.getAnnotations() = " +
+ result);
+ }
+ }
+
+ private static void testEquals(Annotation ann1, Annotation ann2, boolean expectedEquals) {
+ Object result = null;
+ try {
+ try {
+ boolean gotEquals = ann1.equals(ann2);
+ Assert.assertEquals(gotEquals, expectedEquals);
+ result = gotEquals;
+ } catch (Throwable t) {
+ result = t;
+ throw t;
+ }
+ } finally {
+ System.out.println("\n" + ann1 + ".equals(" + ann2 + ") = " + result);
+ }
}
}
--- a/jdk/test/java/lang/annotation/ClassFileGenerator.java Wed Jan 25 14:10:03 2017 +0000
+++ b/jdk/test/java/lang/annotation/ClassFileGenerator.java Wed Jan 25 15:53:17 2017 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, 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
@@ -40,6 +40,13 @@
public static void main(String... args) throws Exception {
classFileWriter("AnnotationWithVoidReturn.class", AnnoationWithVoidReturnDump.dump());
classFileWriter("AnnotationWithParameter.class", AnnoationWithParameterDump.dump());
+ classFileWriter("AnnotationWithExtraInterface.class", AnnotationWithExtraInterfaceDump.dump());
+ classFileWriter("AnnotationWithException.class", AnnotationWithExceptionDump.dump());
+ classFileWriter("AnnotationWithHashCode.class", AnnotationWithHashCodeDump.dump());
+ classFileWriter("AnnotationWithDefaultMember.class", AnnotationWithDefaultMemberDump.dump());
+ classFileWriter("AnnotationWithoutAnnotationAccessModifier.class",
+ AnnotationWithoutAnnotationAccessModifierDump.dump());
+ classFileWriter("HolderX.class", HolderXDump.dump());
}
private static void classFileWriter(String name, byte[] contents) throws IOException {
@@ -49,14 +56,13 @@
}
}
- /*
- Following code create equivalent classfile,
- which is not allowed by javac.
+ /* Following code creates equivalent classfile, which is not allowed by javac:
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationWithVoidReturn {
- void m() default 1;
+ void m() default 1;
}
+
*/
private static class AnnoationWithVoidReturnDump implements Opcodes {
@@ -65,7 +71,7 @@
MethodVisitor mv;
AnnotationVisitor av0;
- cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + +ACC_INTERFACE,
+ cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + ACC_INTERFACE,
"AnnotationWithVoidReturn", null,
"java/lang/Object", new String[]{"java/lang/annotation/Annotation"});
@@ -91,14 +97,13 @@
}
}
- /*
- Following code create equivalent classfile,
- which is not allowed by javac.
+ /* Following code creates equivalent classfile, which is not allowed by javac:
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationWithParameter {
- int m(int x);
+ int m(int x) default -1;
}
+
*/
private static class AnnoationWithParameterDump implements Opcodes {
@@ -136,4 +141,250 @@
}
}
+ /* Following code creates equivalent classfile, which is not allowed by javac:
+
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface AnnotationWithExtraInterface extends java.io.Serializable {
+ int m() default 1;
+ }
+
+ */
+
+ private static class AnnotationWithExtraInterfaceDump implements Opcodes {
+ public static byte[] dump() throws Exception {
+ ClassWriter cw = new ClassWriter(0);
+ MethodVisitor mv;
+ AnnotationVisitor av0;
+
+ cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + ACC_INTERFACE,
+ "AnnotationWithExtraInterface", null,
+ "java/lang/Object", new String[]{"java/lang/annotation/Annotation",
+ "java/io/Serializable"});
+
+ {
+ av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true);
+ av0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;",
+ "RUNTIME");
+ av0.visitEnd();
+ }
+ {
+ mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "m", "()I", null, null);
+ mv.visitEnd();
+ }
+ {
+ av0 = mv.visitAnnotationDefault();
+ av0.visit(null, new Integer(1));
+ av0.visitEnd();
+ }
+ cw.visitEnd();
+
+ return cw.toByteArray();
+ }
+ }
+
+ /* Following code creates equivalent classfile, which is not allowed by javac:
+
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface AnnotationWithException {
+ int m() throws Exception default 1;
+ }
+
+ */
+
+ private static class AnnotationWithExceptionDump implements Opcodes {
+ public static byte[] dump() throws Exception {
+ ClassWriter cw = new ClassWriter(0);
+ MethodVisitor mv;
+ AnnotationVisitor av0;
+
+ cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + ACC_INTERFACE,
+ "AnnotationWithException", null,
+ "java/lang/Object", new String[]{"java/lang/annotation/Annotation"});
+
+ {
+ av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true);
+ av0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;",
+ "RUNTIME");
+ av0.visitEnd();
+ }
+ {
+ mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "m", "()I", null,
+ new String[] {"java/lang/Exception"});
+ mv.visitEnd();
+ }
+ {
+ av0 = mv.visitAnnotationDefault();
+ av0.visit(null, new Integer(1));
+ av0.visitEnd();
+ }
+ cw.visitEnd();
+
+ return cw.toByteArray();
+ }
+ }
+
+ /* Following code creates equivalent classfile, which is not allowed by javac:
+
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface AnnotationWithHashCode {
+ int hashCode() default 1;
+ }
+
+ */
+
+ private static class AnnotationWithHashCodeDump implements Opcodes {
+ public static byte[] dump() throws Exception {
+ ClassWriter cw = new ClassWriter(0);
+ MethodVisitor mv;
+ AnnotationVisitor av0;
+
+ cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + ACC_INTERFACE,
+ "AnnotationWithHashCode", null,
+ "java/lang/Object", new String[]{"java/lang/annotation/Annotation"});
+
+ {
+ av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true);
+ av0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;",
+ "RUNTIME");
+ av0.visitEnd();
+ }
+ {
+ mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "hashCode", "()I", null, null);
+ mv.visitEnd();
+ }
+ {
+ av0 = mv.visitAnnotationDefault();
+ av0.visit(null, new Integer(1));
+ av0.visitEnd();
+ }
+ cw.visitEnd();
+
+ return cw.toByteArray();
+ }
+ }
+
+ /* Following code creates equivalent classfile, which is not allowed by javac:
+
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface AnnotationWithDefaultMember {
+ int m() default 1;
+ default int d() default 2 { return 2; }
+ }
+
+ */
+
+ private static class AnnotationWithDefaultMemberDump implements Opcodes {
+ public static byte[] dump() throws Exception {
+ ClassWriter cw = new ClassWriter(0);
+ MethodVisitor mv, dv;
+ AnnotationVisitor av0;
+
+ cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + ACC_INTERFACE,
+ "AnnotationWithDefaultMember", null,
+ "java/lang/Object", new String[]{"java/lang/annotation/Annotation"});
+
+ {
+ av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true);
+ av0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;",
+ "RUNTIME");
+ av0.visitEnd();
+ }
+ {
+ mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "m", "()I", null, null);
+ mv.visitEnd();
+ }
+ {
+ av0 = mv.visitAnnotationDefault();
+ av0.visit(null, new Integer(1));
+ av0.visitEnd();
+ }
+ {
+ dv = cw.visitMethod(ACC_PUBLIC, "d", "()I", null, null);
+ dv.visitMaxs(1, 1);
+ dv.visitCode();
+ dv.visitInsn(Opcodes.ICONST_2);
+ dv.visitInsn(Opcodes.IRETURN);
+ dv.visitEnd();
+ }
+ {
+ av0 = dv.visitAnnotationDefault();
+ av0.visit(null, new Integer(2));
+ av0.visitEnd();
+ }
+ cw.visitEnd();
+
+ return cw.toByteArray();
+ }
+ }
+
+ /* Following code creates equivalent classfile, which is not allowed by javac:
+
+ @Retention(RetentionPolicy.RUNTIME)
+ public interface AnnotationWithoutAnnotationAccessModifier extends java.lang.annotation.Annotation {
+ int m() default 1;
+ }
+
+ */
+
+ private static class AnnotationWithoutAnnotationAccessModifierDump implements Opcodes {
+ public static byte[] dump() throws Exception {
+ ClassWriter cw = new ClassWriter(0);
+ MethodVisitor mv;
+ AnnotationVisitor av0;
+
+ cw.visit(52, ACC_PUBLIC + /* ACC_ANNOTATION +*/ ACC_ABSTRACT + ACC_INTERFACE,
+ "AnnotationWithoutAnnotationAccessModifier", null,
+ "java/lang/Object", new String[]{"java/lang/annotation/Annotation"});
+
+ {
+ av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true);
+ av0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;",
+ "RUNTIME");
+ av0.visitEnd();
+ }
+ {
+ mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "m", "()I", null, null);
+ mv.visitEnd();
+ }
+ {
+ av0 = mv.visitAnnotationDefault();
+ av0.visit(null, new Integer(1));
+ av0.visitEnd();
+ }
+ cw.visitEnd();
+
+ return cw.toByteArray();
+ }
+ }
+
+ /* Following code creates equivalent classfile, which is not allowed by javac
+ since AnnotationWithoutAnnotationAccessModifier is not marked with ACC_ANNOTATION:
+
+ @GoodAnnotation
+ @AnnotationWithoutAnnotationAccessModifier
+ public interface HolderX {
+ }
+
+ */
+
+ private static class HolderXDump implements Opcodes {
+ public static byte[] dump() throws Exception {
+ ClassWriter cw = new ClassWriter(0);
+
+ cw.visit(52, ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE,
+ "HolderX", null,
+ "java/lang/Object", new String[0]);
+
+ {
+ AnnotationVisitor av0;
+ av0 = cw.visitAnnotation("LGoodAnnotation;", true);
+ av0.visitEnd();
+ av0 = cw.visitAnnotation("LAnnotationWithoutAnnotationAccessModifier;", true);
+ av0.visitEnd();
+ }
+ cw.visitEnd();
+
+ return cw.toByteArray();
+ }
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/annotation/GoodAnnotation.java Wed Jan 25 15:53:17 2017 +0100
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2017, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Simple conforming runtime annotation.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+public @interface GoodAnnotation {}