1 /* 2 * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @bug 8156694 27 * @summary javap should render annotations in a friendly way 28 * @modules jdk.jdeps/com.sun.tools.javap 29 */ 30 31 import java.io.*; 32 import java.lang.annotation.*; 33 import javax.lang.model.element.ElementKind; 34 35 public class AnnoTest { main(String... args)36 public static void main(String... args) throws Exception { 37 new AnnoTest().run(); 38 } 39 run()40 void run() throws Exception { 41 String testClasses = System.getProperty("test.classes"); 42 String out = javap("-v", "-classpath", testClasses, A.class.getName()); 43 44 String nl = System.getProperty("line.separator"); 45 out = out.replaceAll(nl, "\n"); 46 47 if (out.contains("\n\n\n")) 48 error("double blank line found"); 49 50 expect(out, 51 "RuntimeVisibleAnnotations:\n" + 52 " 0: #21(#22=B#23)\n" + 53 " AnnoTest$ByteAnno(\n" + 54 " value=(byte) 42\n" + 55 " )\n" + 56 " 1: #24(#22=S#25)\n" + 57 " AnnoTest$ShortAnno(\n" + 58 " value=(short) 3\n" + 59 " )"); 60 expect(out, 61 "RuntimeInvisibleAnnotations:\n" + 62 " 0: #27(#22=[J#28,J#30,J#32,J#34,J#36])\n" + 63 " AnnoTest$ArrayAnno(\n" + 64 " value=[1l,2l,3l,4l,5l]\n" + 65 " )\n" + 66 " 1: #38(#22=Z#39)\n" + 67 " AnnoTest$BooleanAnno(\n" + 68 " value=false\n" + 69 " )\n" + 70 " 2: #40(#41=c#42)\n" + 71 " AnnoTest$ClassAnno(\n" + 72 " type=class Ljava/lang/Object;\n" + 73 " )\n" + 74 " 3: #43(#44=e#45.#46)\n" + 75 " AnnoTest$EnumAnno(\n" + 76 " kind=Ljavax/lang/model/element/ElementKind;.PACKAGE\n" + 77 " )\n" + 78 " 4: #47(#22=I#48)\n" + 79 " AnnoTest$IntAnno(\n" + 80 " value=2\n" + 81 " )\n" + 82 " 5: #49()\n" + 83 " AnnoTest$IntDefaultAnno\n" + 84 " 6: #50(#51=s#52)\n" + 85 " AnnoTest$NameAnno(\n" + 86 " name=\"NAME\"\n" + 87 " )\n" + 88 " 7: #53(#54=D#55,#57=F#58)\n" + 89 " AnnoTest$MultiAnno(\n" + 90 " d=3.14159d\n" + 91 " f=2.71828f\n" + 92 " )\n" + 93 " 8: #59()\n" + 94 " AnnoTest$SimpleAnno\n" + 95 " 9: #60(#22=@#47(#22=I#61))\n" + 96 " AnnoTest$AnnoAnno(\n" + 97 " value=@AnnoTest$IntAnno(\n" + 98 " value=5\n" + 99 " )\n" + 100 " )"); 101 expect(out, 102 "RuntimeInvisibleTypeAnnotations:\n" + 103 " 0: #63(): CLASS_EXTENDS, type_index=0\n" + 104 " AnnoTest$TypeAnno"); 105 106 if (errors > 0) 107 throw new Exception(errors + " errors found"); 108 } 109 javap(String... args)110 String javap(String... args) throws Exception { 111 StringWriter sw = new StringWriter(); 112 int rc; 113 try (PrintWriter out = new PrintWriter(sw)) { 114 rc = com.sun.tools.javap.Main.run(args, out); 115 } 116 System.out.println(sw.toString()); 117 if (rc < 0) 118 throw new Exception("javap exited, rc=" + rc); 119 return sw.toString(); 120 } 121 expect(String text, String expect)122 void expect(String text, String expect) { 123 if (!text.contains(expect)) 124 error("expected text not found"); 125 } 126 error(String msg)127 void error(String msg) { 128 System.out.println("Error: " + msg); 129 errors++; 130 } 131 132 int errors; 133 134 /* Simple test classes to run through javap. */ 135 public @interface SimpleAnno { } value()136 public @interface BooleanAnno { boolean value(); } value()137 public @interface IntAnno { int value(); } value()138 public @interface IntDefaultAnno { int value() default 3; } 139 140 @Retention(RetentionPolicy.RUNTIME) value()141 public @interface ByteAnno { byte value(); } 142 143 @Retention(RetentionPolicy.RUNTIME) value()144 public @interface ShortAnno { short value(); } 145 name()146 public @interface NameAnno { String name(); } value()147 public @interface ArrayAnno { long[] value(); } kind()148 public @interface EnumAnno { ElementKind kind(); } type()149 public @interface ClassAnno { Class<?> type(); } d()150 public @interface MultiAnno { float f(); double d(); } 151 value()152 public @interface AnnoAnno { IntAnno value(); } 153 154 @Target(ElementType.TYPE_USE) 155 public @interface TypeAnno { } 156 157 @ArrayAnno({1, 2, 3, 4, 5}) 158 @BooleanAnno(false) 159 @ByteAnno(42) 160 @ClassAnno(type = Object.class) 161 @EnumAnno(kind = ElementKind.PACKAGE) 162 @IntAnno(2) 163 @IntDefaultAnno 164 @NameAnno(name = "NAME") 165 @MultiAnno(d = 3.14159, f = 2.71828f) 166 @ShortAnno(3) 167 @SimpleAnno 168 @AnnoAnno(@IntAnno(5)) 169 public abstract class A implements @TypeAnno Runnable { } 170 } 171