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