1 /* 2 * Copyright (c) 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 8046171 27 * @summary Test the new nestmate reflection API 28 * @compile TestReflectionAPI.java 29 * PackagedNestHost.java 30 * PackagedNestHost2.java 31 * SampleNest.java 32 * Hosts.java 33 * InvalidNestHost.java 34 * 35 * @compile MemberNoHost.jcod 36 * MemberMissingHost.jcod 37 * MemberNotInstanceHost.jcod 38 * MemberNotOurHost.jcod 39 * MemberMalformedHost.jcod 40 * MalformedHost.jcod 41 * PackagedNestHost.jcod 42 * PackagedNestHost2Member.jcod 43 * PackagedNestHostMember.jcod 44 * HostOfMemberNoHost.jcod 45 * HostOfMemberMissingHost.jcod 46 * HostOfMemberNotInstanceHost.jcod 47 * HostOfMemberNotOurHost.jcod 48 * HostOfMemberMalformedHost.jcod 49 * HostWithSelfMember.jcod 50 * HostWithDuplicateMembers.jcod 51 * 52 * @run main/othervm TestReflectionAPI 53 */ 54 55 // We need a nest member class that is invalid for each of the possible reasons, 56 // plus we need some external classes to test other failure modes. 57 // For each nested class below there is a corresponding .jcod file which breaks one 58 // of the rules regarding nest membership. For the package related tests we have 59 // additional PackageNestHost*.java sources. 60 // For testing getNestMembers we need an external host class that has a nested class 61 // which we can form a jcod file from such that we get all the expected failure modes. 62 // Note that all the .java files must be compiled in the same step, while all 63 // .jcod files must be compiled in a later step. 64 65 import java.util.Arrays; 66 import java.util.Comparator; 67 import java.util.HashSet; 68 69 public class TestReflectionAPI { 70 71 // Valid nest member 72 static class Member {} 73 74 // Missing NestHost attribute 75 static class MemberNoHost {} 76 77 // Missing NestHost class 78 static class MemberMissingHost {} 79 80 // Invalid NestHost class (not instance class) 81 static class MemberNotInstanceHost { 82 Object[] oa; // create CP entry to use in jcod change 83 } 84 85 // Valid but different NestHost class 86 static class MemberNotOurHost {} 87 88 // Malformed NestHost class 89 static class MemberMalformedHost {} 90 91 public static void main(String[] args) throws Throwable { 92 test_getNestHost(); 93 test_isNestmateOf(); 94 test_getNestMembers(); 95 } 96 97 static void test_getNestHost() { 98 Class<?> host = TestReflectionAPI.class; 99 100 // sampling of "good" checks 101 102 checkHost(host, host); 103 checkHost(Member.class, host); 104 Runnable r = new Runnable() { public void run() {}}; 105 checkHost(r.getClass(), host); 106 107 // all the "bad" classes should report themselves as their 108 // own nest host - no exceptions should be thrown 109 Class<?>[] allClasses = host.getDeclaredClasses(); 110 for (Class<?> c : allClasses) { 111 if (c == Member.class) 112 continue; 113 checkHost(c, c); 114 } 115 checkHost(P1.PackagedNestHost.Member.class, 116 P1.PackagedNestHost.Member.class); 117 checkHost(P2.PackagedNestHost2.Member.class, 118 P2.PackagedNestHost2.Member.class); 119 120 // test some 'special' classes 121 checkHost(int.class, int.class); // primitive 122 checkHost(Object[].class, Object[].class); // array 123 checkHost(Thread.State.class, Thread.class); // enum 124 checkHost(java.lang.annotation.Documented.class, // annotation 125 java.lang.annotation.Documented.class); 126 } 127 128 static void test_isNestmateOf() { 129 Class<?> host = TestReflectionAPI.class; 130 checkNestmates(host, host, true); 131 checkNestmates(Member.class, host, true); 132 Runnable r = new Runnable() { public void run() {}}; 133 checkNestmates(r.getClass(), host, true); 134 135 // all the "bad" classes should report themselves as their 136 // own nest host - no exceptions should be thrown - so not 137 // nestmates 138 Class<?>[] allClasses = host.getDeclaredClasses(); 139 for (Class<?> c : allClasses) { 140 if (c == Member.class) 141 continue; 142 checkNestmates(host, c, false); 143 } 144 145 // 'special' classes 146 checkNestmates(int.class, int.class, true); // primitive 147 checkNestmates(int.class, long.class, false); // primitive 148 checkNestmates(Object[].class, Object[].class, true); // array 149 checkNestmates(Object[].class, int[].class, false); // array 150 checkNestmates(Thread.State.class, Thread.class, true); // enum 151 checkNestmates(java.lang.annotation.Documented.class, // annotation 152 java.lang.annotation.Documented.class, true); 153 } 154 155 static void test_getNestMembers() { 156 // Sampling of "good" checks 157 Class<?>[] good = { Object.class, Object[].class, int.class}; 158 checkSingletonNests(good); 159 160 // More thorough correctness check 161 checkNest(SampleNest.class, SampleNest.nestedTypes(), false); 162 163 // Special cases - legal but not produced by javac 164 checkNest(HostWithSelfMember.class, 165 new Class<?>[] { HostWithSelfMember.class, 166 HostWithSelfMember.Member.class }, 167 true); 168 checkNest(HostWithDuplicateMembers.class, 169 new Class<?>[] { HostWithDuplicateMembers.class, 170 HostWithDuplicateMembers.Member1.class, 171 HostWithDuplicateMembers.Member2.class }, 172 true); 173 174 // Hosts with "bad" members 175 Class<?>[] bad = { 176 HostOfMemberNoHost.class, 177 HostOfMemberMissingHost.class, 178 HostOfMemberNotOurHost.class, 179 HostOfMemberNotInstanceHost.class, 180 HostOfMemberMalformedHost.class, 181 }; 182 Class<?>[] exceptions = { 183 IncompatibleClassChangeError.class, 184 NoClassDefFoundError.class, 185 IncompatibleClassChangeError.class, 186 IncompatibleClassChangeError.class, 187 ClassFormatError.class, 188 }; 189 String[] messages = { 190 "Nest member HostOfMemberNoHost$MemberNoHost in HostOfMemberNoHost " + 191 "declares a different nest host of HostOfMemberNoHost$MemberNoHost", 192 "Unable to load nest-host class (NestHost) of " + 193 "HostOfMemberMissingHost$MemberMissingHost", 194 "Type HostOfMemberNotOurHost$MemberNotOurHost is not a nest member " + 195 "of InvalidNestHost: current type is not listed as a nest member", 196 "Type HostOfMemberNotInstanceHost$MemberNotInstanceHost is not a nest " + 197 "member of [LInvalidNestHost;: current type is not listed as a nest member", 198 "Incompatible magic value 3735928559 in class file MalformedHost", 199 }; 200 for (int i = 0; i < bad.length; i++) { 201 try { 202 bad[i].getNestMembers(); 203 throw new Error("getNestMembers() succeeded for class " + 204 bad[i].getName()); 205 } catch (LinkageError e) { 206 checkException(e, messages[i], exceptions[i]); 207 } 208 } 209 } 210 211 static void checkException(Throwable actual, String msg, Class<?> expected) { 212 if (!actual.getClass().equals(expected)) 213 throw new Error("Unexpected exception: got " + actual.getClass().getName() 214 + " but expected " + expected.getName()); 215 if (!actual.getMessage().contains(msg)) 216 throw new Error("Wrong " + actual.getClass().getSimpleName() +": \"" + 217 actual.getMessage() + "\" does not contain \"" + 218 msg + "\""); 219 System.out.println("OK - got expected exception: " + actual); 220 } 221 222 static void checkHost(Class<?> target, Class<?> expected) { 223 System.out.println("Checking nest host of " + target.getName()); 224 Class<?> host = target.getNestHost(); 225 if (host != expected) 226 throw new Error("Class " + target.getName() + 227 " has nest host " + host.getName() + 228 " but expected " + expected.getName()); 229 } 230 231 static void checkNestmates(Class<?> a, Class<?> b, boolean mates) { 232 System.out.println("Checking if " + a.getName() + 233 " isNestmateOf " + b.getName()); 234 235 if (a.isNestmateOf(b) != mates) 236 throw new Error("Class " + a.getName() + " is " + 237 (mates ? "not " : "") + 238 "a nestmate of " + b.getName() + " but should " + 239 (mates ? "" : "not ") + "be"); 240 } 241 242 static Comparator<Class<?>> cmp = Comparator.comparing(Class::getName); 243 244 static void checkNest(Class<?> host, Class<?>[] unsortedTypes, boolean expectDups) { 245 Class<?>[] members = host.getNestMembers(); 246 Arrays.sort(members, cmp); 247 Class<?>[] nestedTypes = unsortedTypes.clone(); 248 Arrays.sort(nestedTypes, cmp); 249 printMembers(host, members); 250 printDeclared(host, nestedTypes); 251 if (!Arrays.equals(members, nestedTypes)) { 252 if (!expectDups) { 253 throw new Error("Class " + host.getName() + " has different members " + 254 "compared to declared classes"); 255 } 256 else { 257 // get rid of duplicates 258 Class<?>[] memberSet = 259 new HashSet<Class<?>>(Arrays.asList(members)).toArray(new Class<?>[0]); 260 Arrays.sort(memberSet, cmp); 261 if (!Arrays.equals(memberSet, nestedTypes)) { 262 throw new Error("Class " + host.getName() + " has different members " + 263 "compared to declared classes, even after duplicate removal"); 264 } 265 } 266 } 267 // verify all the relationships that must hold for nest members 268 for (Class<?> a : members) { 269 checkHost(a, host); 270 checkNestmates(a, host, true); 271 Class<?>[] aMembers = a.getNestMembers(); 272 if (aMembers[0] != host) { 273 throw new Error("Class " + a.getName() + " getNestMembers()[0] = " + 274 aMembers[0].getName() + " not " + host.getName()); 275 276 } 277 Arrays.sort(aMembers, cmp); 278 if (!Arrays.equals(members, aMembers)) { 279 throw new Error("Class " + a.getName() + " has different members " + 280 "compared to host " + host.getName()); 281 } 282 for (Class<?> b : members) { 283 checkNestmates(a, b, true); 284 } 285 } 286 } 287 288 static void checkSingletonNests(Class<?>[] classes) { 289 for (Class<?> host : classes) { 290 Class<?>[] members = host.getNestMembers(); 291 if (members.length != 1) { 292 printMembers(host, members); 293 throw new Error("Class " + host.getName() + " lists " + members.length 294 + " members instead of 1 (itself)"); 295 } 296 if (members[0] != host) { 297 printMembers(host, members); 298 throw new Error("Class " + host.getName() + " lists " + 299 members[0].getName() + " as member instead of itself"); 300 } 301 } 302 } 303 304 static void printMembers(Class<?> host, Class<?>[] members) { 305 System.out.println("Class " + host.getName() + " has members: "); 306 for (Class<?> c : members) { 307 System.out.println(" - " + c.getName()); 308 } 309 } 310 311 static void printDeclared(Class<?> host, Class<?>[] declared) { 312 System.out.println("Class " + host.getName() + " has declared types: "); 313 for (Class<?> c : declared) { 314 System.out.println(" - " + c.getName()); 315 } 316 } 317 318 }