changeset 16556:c7d93950979d

Merge
author plevart
date Wed, 25 Jan 2017 15:53:17 +0100
parents e8dab4820716 9ecf1f5bc96c
children 5c7dda0aa8ce
files
diffstat 3 files changed, 666 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/test/java/lang/annotation/AnnotationVerifier.java	Wed Jan 25 14:10:03 2017 +0000
+++ b/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 {
 
-    @AnnotationWithParameter
-    @AnnotationWithVoidReturn
-    static class BadAnnotation {
+    //=======================================================
+    // GoodAnnotation...
+
+    @GoodAnnotation
+    static class HolderA {
     }
 
     @Test
-    @ExpectedExceptions(IllegalArgumentException.class)
-    public void annotationValidationIAE() {
-        AnnotationType.getInstance(AnnotationWithParameter.class);
+    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 HolderC {
     }
 
     @Test(expectedExceptions = AnnotationFormatError.class)
-    public void annotationValidationAFE() {
-        BadAnnotation.class.getAnnotation(AnnotationWithVoidReturn.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
+    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 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/test/java/lang/annotation/ClassFileGenerator.java	Wed Jan 25 14:10:03 2017 +0000
+++ b/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/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 {}