1/* 2 * Copyright (c) 2013, 2015, 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 8005085 8008762 8008751 8013065 8015323 8015257 27 * @summary Type annotations on anonymous and inner class. 28 * Six TYPE_USE annotations are repeated(or not); Four combinations create 29 * four test files, and each results in the test class and 2 anonymous classes. 30 * Each element of these three classes is checked for expected number of the 31 * four annotation Attributes. Expected annotation counts depend on type of 32 * annotation place on type of element (a FIELD&TYPE_USE element on a field 33 * results in 2). Elements with no annotations expect 0. 34 * Source template is read in from testanoninner.template 35 * 36 * @modules jdk.jdeps/com.sun.tools.classfile 37 */ 38import java.lang.annotation.*; 39import java.io.*; 40import java.util.List; 41import java.util.LinkedList; 42import com.sun.tools.classfile.*; 43import java.nio.file.Files; 44import java.nio.charset.*; 45import java.io.File; 46import java.io.IOException; 47 48 49import java.lang.annotation.*; 50import static java.lang.annotation.RetentionPolicy.*; 51import static java.lang.annotation.ElementType.*; 52 53/* 54 * A source template is read in and testname and annotations are inserted 55 * via replace(). 56 */ 57public class TestAnonInnerClasses extends ClassfileTestHelper { 58 // tally errors and test cases 59 int errors = 0; 60 int checks = 0; 61 //Note expected test count in case of skips due to bugs. 62 int tc = 0, xtc = 180; // 45 x 4 variations of repeated annotations. 63 File testSrc = new File(System.getProperty("test.src")); 64 65 String[] AnnoAttributes = { 66 Attribute.RuntimeVisibleTypeAnnotations, 67 Attribute.RuntimeInvisibleTypeAnnotations, 68 Attribute.RuntimeVisibleAnnotations, 69 Attribute.RuntimeInvisibleAnnotations 70 }; 71 72 // template for source files 73 String srcTemplate = "testanoninner.template"; 74 75 // Four test files generated based on combinations of repeating annotations. 76 Boolean As= false, Bs=true, Cs=false, Ds=false, TAs=false,TBs=false; 77 Boolean[][] bRepeat = new Boolean[][]{ 78 /* no repeats */ {false, false, false, false, false, false}, 79 /* repeat A,C,TA */ {true, false, true, false, true, false}, 80 /* repeat B,D,TB */ {false, true, false, true, false, true}, 81 /* repeat all */ {true, true, true, true, true, true} 82 }; 83 // Save descriptions of failed test case; does not terminate upon a failure. 84 List<String> failed = new LinkedList<>(); 85 86 public static void main(String[] args) throws Exception { 87 new TestAnonInnerClasses().run(); 88 } 89 90 // Check annotation counts and make reports sufficiently descriptive to 91 // easily diagnose. 92 void check(String testcase, int vtaX, int itaX, int vaX, int iaX, 93 int vtaA, int itaA, int vaA, int iaA) { 94 95 String descr = " checking " + testcase+" _TYPE_, expected: " + 96 vtaX + ", " + itaX + ", " + vaX + ", " + iaX + "; actual: " + 97 vtaA + ", " + itaA + ", " + vaA + ", " + iaA; 98 String description; 99 description=descr.replace("_TYPE_","RuntimeVisibleTypeAnnotations"); 100 if (vtaX != vtaA) { 101 errors++; 102 failed.add(++checks + " " + testcase + ": (vtaX) " + vtaX + 103 " != " + vtaA + " (vtaA)"); 104 println(checks + " FAIL: " + description); 105 } else { 106 println(++checks + " PASS: " + description); 107 } 108 description=descr.replace("_TYPE_","RuntimeInvisibleTypeAnnotations"); 109 if (itaX != itaA) { 110 errors++; 111 failed.add(++checks + " " + testcase + ": (itaX) " + itaX + " != " + 112 itaA + " (itaA)"); 113 println(checks + " FAIL: " + description); 114 } else { 115 println(++checks + " PASS: " + description); 116 } 117 description=descr.replace("_TYPE_","RuntimeVisibleAnnotations"); 118 if (vaX != vaA) { 119 errors++; 120 failed.add(++checks + " " + testcase + ": (vaX) " + vaX + " != " + 121 vaA + " (vaA)"); 122 println(checks + " FAIL: " + description); 123 } else { 124 println(++checks + " PASS: " + description); 125 } 126 description=descr.replace("_TYPE_","RuntimeInvisibleAnnotations"); 127 if (iaX != iaA) { 128 errors++; 129 failed.add(++checks + " " + testcase + ": (iaX) " + iaX + " != " + 130 iaA + " (iaA)"); 131 println(checks + " FAIL: " + description); 132 } else { 133 println(++checks + " PASS: " + description); 134 } 135 println(""); 136 } 137 138 // Print failed cases (if any) and throw exception for fail. 139 void report() { 140 if (errors!=0) { 141 System.err.println("Failed tests: " + errors + 142 "\nfailed test cases:\n"); 143 for (String t: failed) System.err.println(" " + t); 144 throw new RuntimeException("FAIL: There were test failures."); 145 } else 146 System.out.println("PASSED all tests."); 147 } 148 149 void test(String ttype, ClassFile cf, Method m, Field f, boolean visible) { 150 int vtaActual = 0, 151 itaActual = 0, 152 vaActual = 0, 153 iaActual = 0, 154 vtaExp = 0, 155 itaExp = 0, 156 vaExp = 0, 157 iaExp = 0, 158 index = 0, 159 index2 = 0; 160 String memberName = null, 161 testcase = "undefined", 162 testClassName = null; 163 Attribute attr = null, 164 cattr = null; 165 Code_attribute CAttr = null; 166 // Get counts of 4 annotation Attributes on element being checked. 167 for (String AnnoType : AnnoAttributes) { 168 try { 169 switch (ttype) { 170 case "METHOD": 171 index = m.attributes.getIndex(cf.constant_pool, 172 AnnoType); 173 memberName = m.getName(cf.constant_pool); 174 if (index != -1) 175 attr = m.attributes.get(index); 176 //fetch index annotations from code attribute. 177 index2 = m.attributes.getIndex(cf.constant_pool, 178 Attribute.Code); 179 if (index2 != -1) { 180 cattr = m.attributes.get(index2); 181 assert cattr instanceof Code_attribute; 182 CAttr = (Code_attribute)cattr; 183 index2 = CAttr.attributes.getIndex(cf.constant_pool, 184 AnnoType); 185 if (index2 != -1) 186 cattr = CAttr.attributes.get(index2); 187 } 188 break; 189 case "FIELD": 190 index = f.attributes.getIndex(cf.constant_pool, 191 AnnoType); 192 memberName = f.getName(cf.constant_pool); 193 if (index != -1) 194 attr = f.attributes.get(index); 195 //fetch index annotations from code attribute. 196 index2 = cf.attributes.getIndex(cf.constant_pool, 197 Attribute.Code); 198 if (index2!= -1) { 199 cattr = cf.attributes.get(index2); 200 assert cattr instanceof Code_attribute; 201 CAttr = (Code_attribute)cattr; 202 index2 = CAttr.attributes.getIndex(cf.constant_pool, 203 AnnoType); 204 if (index2!= -1) 205 cattr = CAttr.attributes.get(index2); 206 } 207 break; 208 209 default: 210 memberName = cf.getName(); 211 index = cf.attributes.getIndex(cf.constant_pool, 212 AnnoType); 213 if (index!= -1) attr = cf.attributes.get(index); 214 break; 215 } 216 } 217 catch (ConstantPoolException cpe) { cpe.printStackTrace(); } 218 try { 219 testClassName=cf.getName(); 220 testcase = ttype + ": " + testClassName + ": " + 221 memberName + ", "; 222 } 223 catch (ConstantPoolException cpe) { cpe.printStackTrace(); } 224 if (index != -1) { 225 switch (AnnoType) { 226 case Attribute.RuntimeVisibleTypeAnnotations: 227 //count RuntimeVisibleTypeAnnotations 228 RuntimeVisibleTypeAnnotations_attribute RVTAa = 229 (RuntimeVisibleTypeAnnotations_attribute)attr; 230 vtaActual += RVTAa.annotations.length; 231 break; 232 case Attribute.RuntimeVisibleAnnotations: 233 //count RuntimeVisibleAnnotations 234 RuntimeVisibleAnnotations_attribute RVAa = 235 (RuntimeVisibleAnnotations_attribute)attr; 236 vaActual += RVAa.annotations.length; 237 break; 238 case Attribute.RuntimeInvisibleTypeAnnotations: 239 //count RuntimeInvisibleTypeAnnotations 240 RuntimeInvisibleTypeAnnotations_attribute RITAa = 241 (RuntimeInvisibleTypeAnnotations_attribute)attr; 242 itaActual += RITAa.annotations.length; 243 break; 244 case Attribute.RuntimeInvisibleAnnotations: 245 //count RuntimeInvisibleAnnotations 246 RuntimeInvisibleAnnotations_attribute RIAa = 247 (RuntimeInvisibleAnnotations_attribute)attr; 248 iaActual += RIAa.annotations.length; 249 break; 250 } 251 } 252 // annotations from code attribute. 253 if (index2 != -1) { 254 switch (AnnoType) { 255 case Attribute.RuntimeVisibleTypeAnnotations: 256 //count RuntimeVisibleTypeAnnotations 257 RuntimeVisibleTypeAnnotations_attribute RVTAa = 258 (RuntimeVisibleTypeAnnotations_attribute)cattr; 259 vtaActual += RVTAa.annotations.length; 260 break; 261 case Attribute.RuntimeVisibleAnnotations: 262 //count RuntimeVisibleAnnotations 263 RuntimeVisibleAnnotations_attribute RVAa = 264 (RuntimeVisibleAnnotations_attribute)cattr; 265 vaActual += RVAa.annotations.length; 266 break; 267 case Attribute.RuntimeInvisibleTypeAnnotations: 268 //count RuntimeInvisibleTypeAnnotations 269 RuntimeInvisibleTypeAnnotations_attribute RITAa = 270 (RuntimeInvisibleTypeAnnotations_attribute)cattr; 271 itaActual += RITAa.annotations.length; 272 break; 273 case Attribute.RuntimeInvisibleAnnotations: 274 //count RuntimeInvisibleAnnotations 275 RuntimeInvisibleAnnotations_attribute RIAa = 276 (RuntimeInvisibleAnnotations_attribute)cattr; 277 iaActual += RIAa.annotations.length; 278 break; 279 } 280 } 281 } 282 283 switch (memberName) { 284 //METHODs 285 case "test" : vtaExp=4; itaExp=4; vaExp=0; iaExp=0; tc++; break; 286 case "mtest": vtaExp=4; itaExp=4; vaExp=1; iaExp=1; tc++; break; 287 case "m1": vtaExp=2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 288 case "m2": vtaExp=4; itaExp=4; vaExp=1; iaExp=1; tc++; break; 289 case "m3": vtaExp=10; itaExp=10; vaExp=1; iaExp=1; tc++; break; 290 case "tm": vtaExp=6; itaExp=6; vaExp=1; iaExp=1; tc++; break; 291 //inner class 292 case "i_m1": vtaExp=2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 293 case "i_m2": vtaExp=4; itaExp=4; vaExp=1; iaExp=1; tc++; break; 294 case "i_um": vtaExp=6; itaExp=6; vaExp=1; iaExp=1; tc++; break; 295 //local class 296 case "l_m1": vtaExp=2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 297 case "l_m2": vtaExp=4; itaExp=4; vaExp=1; iaExp=1; tc++; break; 298 case "l_um": vtaExp=6; itaExp=6; vaExp=1; iaExp=1; tc++; break; 299 //anon class 300 case "mm_m1": vtaExp=2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 301 case "mm_m2": vtaExp=4; itaExp=4; vaExp=1; iaExp=1; tc++; break; 302 case "mm_m3": vtaExp=10; itaExp=10;vaExp=1; iaExp=1; tc++; break; 303 case "mm_tm": vtaExp=6; itaExp=6; vaExp=1; iaExp=1; tc++; break; 304 //InnerAnon class 305 case "ia_m1": vtaExp=2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 306 case "ia_m2": vtaExp=4; itaExp=4; vaExp=1; iaExp=1; tc++; break; 307 case "ia_um": vtaExp=6; itaExp=6; vaExp=1; iaExp=1; tc++; break; 308 //FIELDs 309 case "data": vtaExp = 2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 310 case "odata1": vtaExp = 2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 311 case "pdata1": vtaExp = 2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 312 case "tdata": vtaExp = 2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 313 case "sa1": vtaExp = 6; itaExp=6; vaExp=1; iaExp=1; tc++; break; 314 //inner class 315 case "i_odata1": vtaExp=2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 316 case "i_pdata1": vtaExp=2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 317 case "i_udata": vtaExp=2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 318 case "i_sa1": vtaExp=6; itaExp=6; vaExp=1; iaExp=1; tc++; break; 319 case "i_tdata": vtaExp=2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 320 //local class 321 case "l_odata1": vtaExp=2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 322 case "l_pdata1": vtaExp=2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 323 case "l_udata": vtaExp=2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 324 case "l_sa1": vtaExp=6; itaExp=6; vaExp=1; iaExp=1; tc++; break; 325 case "l_tdata": vtaExp=2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 326 //anon class 327 case "mm_odata1": vtaExp = 2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 328 case "mm_pdata1": vtaExp = 2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 329 case "mm_sa1": vtaExp = 6; itaExp=6; vaExp=1; iaExp=1; tc++; break; 330 case "mm_tdata": vtaExp = 2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 331 // InnerAnon class 332 case "ia_odata1": vtaExp=2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 333 case "ia_pdata1": vtaExp=2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 334 case "ia_udata": vtaExp=2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 335 case "ia_sa1": vtaExp=6; itaExp=6; vaExp=1; iaExp=1; tc++; break; 336 case "ia_tdata": vtaExp=2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 337 case "IA": vtaExp=4; itaExp=4; vaExp=1; iaExp=1; tc++; break; 338 case "IN": vtaExp=4; itaExp=4; vaExp=1; iaExp=1; tc++; break; 339 // default cases are <init>, this$0, this$1, mmtest, atest 340 default: vtaExp = 0; itaExp=0; vaExp=0; iaExp=0; break; 341 } 342 check(testcase,vtaExp, itaExp, vaExp, iaExp, 343 vtaActual,itaActual,vaActual,iaActual); 344 } 345 346 public void run() { 347 ClassFile cf = null; 348 InputStream in = null; 349 int testcount = 1; 350 File testFile = null; 351 // Generate source, check methods and fields for each combination. 352 for (Boolean[] bCombo : bRepeat) { 353 As=bCombo[0]; Bs=bCombo[1]; Cs=bCombo[2]; 354 Ds=bCombo[3]; TAs=bCombo[4]; TBs=bCombo[5]; 355 String testname = "Test" + testcount++; 356 println("Combinations: " + As + ", " + Bs + ", " + Cs + ", " + Ds + 357 ", " + TAs + ", " + TBs + 358 "; see " + testname + ".java"); 359 String[] classes = {testname + ".class", 360 testname + "$Inner.class", 361 testname + "$1Local1.class", 362 testname + "$1.class", 363 testname + "$1$1.class", 364 testname + "$1$InnerAnon.class" 365 }; 366 // Create test source, create and compile File. 367 String sourceString = getSource(srcTemplate, testname, 368 As, Bs, Cs, Ds, TAs, TBs); 369 System.out.println(sourceString); 370 try { 371 testFile = writeTestFile(testname+".java", sourceString); 372 } 373 catch (IOException ioe) { ioe.printStackTrace(); } 374 // Compile test source and read classfile. 375 File classFile = null; 376 try { 377 classFile = compile(testFile); 378 } 379 catch (Error err) { 380 System.err.println("FAILED compile. Source:\n" + sourceString); 381 throw err; 382 } 383 String testloc = classFile.getAbsolutePath().substring( 384 0,classFile.getAbsolutePath().indexOf(classFile.getPath())); 385 for (String clazz : classes) { 386 try { 387 cf = ClassFile.read(new File(testloc+clazz)); 388 } 389 catch (Exception e) { e.printStackTrace(); } 390 // Test for all methods and fields 391 for (Method m: cf.methods) { 392 test("METHOD", cf, m, null, true); 393 } 394 for (Field f: cf.fields) { 395 test("FIELD", cf, null, f, true); 396 } 397 } 398 } 399 report(); 400 if (tc!=xtc) System.out.println("Test Count: " + tc + " != " + 401 "expected: " + xtc); 402 } 403 404 405 String getSrcTemplate(String sTemplate) { 406 List<String> tmpl = null; 407 String sTmpl = ""; 408 try { 409 tmpl = Files.readAllLines(new File(testSrc,sTemplate).toPath(), 410 Charset.defaultCharset()); 411 } 412 catch (IOException ioe) { 413 String error = "FAILED: Test failed to read template" + sTemplate; 414 ioe.printStackTrace(); 415 throw new RuntimeException(error); 416 } 417 for (String l : tmpl) 418 sTmpl=sTmpl.concat(l).concat("\n"); 419 return sTmpl; 420 } 421 422 // test class template 423 String getSource(String templateName, String testname, 424 Boolean Arepeats, Boolean Brepeats, 425 Boolean Crepeats, Boolean Drepeats, 426 Boolean TArepeats, Boolean TBrepeats) { 427 String As = Arepeats ? "@A @A":"@A", 428 Bs = Brepeats ? "@B @B":"@B", 429 Cs = Crepeats ? "@C @C":"@C", 430 Ds = Drepeats ? "@D @D":"@D", 431 TAs = TArepeats ? "@TA @TA":"@TA", 432 TBs = TBrepeats ? "@TB @TB":"@TB"; 433 434 // split up replace() lines for readability 435 String testsource = getSrcTemplate(templateName).replace("testname",testname); 436 testsource = testsource.replace("_As",As).replace("_Bs",Bs).replace("_Cs",Cs); 437 testsource = testsource.replace("_Ds",Ds).replace("_TAs",TAs).replace("_TBs",TBs); 438 return testsource; 439 } 440} 441