RevealDirectTest.java revision 8729:0242fce0f717
1/* 2 * Copyright (c) 2013, 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 * @summary verify Lookup.revealDirect on a variety of input handles 27 * @compile -XDignore.symbol.file RevealDirectTest.java 28 * @run junit/othervm -ea -esa test.java.lang.invoke.RevealDirectTest 29 * 30 * @test 31 * @summary verify Lookup.revealDirect on a variety of input handles, with security manager 32 * @run main/othervm/policy=jtreg.security.policy/secure=java.lang.SecurityManager -ea -esa test.java.lang.invoke.RevealDirectTest 33 */ 34 35/* To run manually: 36 * $ $JAVA8X_HOME/bin/javac -cp $JUNIT4_JAR -d ../../../.. -XDignore.symbol.file RevealDirectTest.java 37 * $ $JAVA8X_HOME/bin/java -cp $JUNIT4_JAR:../../../.. -ea -esa org.junit.runner.JUnitCore test.java.lang.invoke.RevealDirectTest 38 * $ $JAVA8X_HOME/bin/java -cp $JUNIT4_JAR:../../../.. -ea -esa -Djava.security.manager test.java.lang.invoke.RevealDirectTest 39 */ 40 41package test.java.lang.invoke; 42 43import java.lang.reflect.*; 44import java.lang.invoke.*; 45import static java.lang.invoke.MethodHandles.*; 46import static java.lang.invoke.MethodType.*; 47import static java.lang.invoke.MethodHandleInfo.*; 48import java.util.*; 49import static org.junit.Assert.*; 50import org.junit.*; 51 52public class RevealDirectTest { 53 public static void main(String... av) throws Throwable { 54 // Run the @Test methods explicitly, in case we don't want to use the JUnitCore driver. 55 // This appears to be necessary when running with a security manager. 56 Throwable fail = null; 57 for (Method test : RevealDirectTest.class.getDeclaredMethods()) { 58 if (!test.isAnnotationPresent(Test.class)) continue; 59 try { 60 test.invoke(new RevealDirectTest()); 61 } catch (Throwable ex) { 62 if (ex instanceof InvocationTargetException) 63 ex = ex.getCause(); 64 if (fail == null) fail = ex; 65 System.out.println("Testcase: "+test.getName() 66 +"("+test.getDeclaringClass().getName() 67 +"):\tCaused an ERROR"); 68 System.out.println(ex); 69 ex.printStackTrace(System.out); 70 } 71 } 72 if (fail != null) throw fail; 73 } 74 75 public interface SimpleSuperInterface { 76 public abstract int getInt(); 77 public static void printAll(String... args) { 78 System.out.println(Arrays.toString(args)); 79 } 80 public int NICE_CONSTANT = 42; 81 } 82 public interface SimpleInterface extends SimpleSuperInterface { 83 default float getFloat() { return getInt(); } 84 public static void printAll(String[] args) { 85 System.out.println(Arrays.toString(args)); 86 } 87 } 88 public static class Simple implements SimpleInterface, Cloneable { 89 public int intField; 90 public final int finalField; 91 private static String stringField; 92 public int getInt() { return NICE_CONSTANT; } 93 private static Number getNum() { return 804; } 94 public Simple clone() { 95 try { 96 return (Simple) super.clone(); 97 } catch (CloneNotSupportedException ex) { 98 throw new RuntimeException(ex); 99 } 100 } 101 Simple() { finalField = -NICE_CONSTANT; } 102 private static Lookup localLookup() { return lookup(); } 103 private static List<Member> members() { return getMembers(lookup().lookupClass()); }; 104 } 105 static class Nestmate { 106 private static Lookup localLookup() { return lookup(); } 107 } 108 109 static boolean VERBOSE = false; 110 111 @Test public void testSimple() throws Throwable { 112 if (VERBOSE) System.out.println("@Test testSimple"); 113 testOnMembers("testSimple", Simple.members(), Simple.localLookup()); 114 } 115 @Test public void testPublicLookup() throws Throwable { 116 if (VERBOSE) System.out.println("@Test testPublicLookup"); 117 List<Member> mems = publicOnly(Simple.members()); 118 Lookup pubLookup = publicLookup(), privLookup = Simple.localLookup(); 119 testOnMembers("testPublicLookup/1", mems, pubLookup); 120 // reveal using publicLookup: 121 testOnMembers("testPublicLookup/2", mems, privLookup, pubLookup); 122 // lookup using publicLookup, but reveal using private: 123 testOnMembers("testPublicLookup/3", mems, pubLookup, privLookup); 124 } 125 @Test public void testPublicLookupNegative() throws Throwable { 126 if (VERBOSE) System.out.println("@Test testPublicLookupNegative"); 127 List<Member> mems = nonPublicOnly(Simple.members()); 128 Lookup pubLookup = publicLookup(), privLookup = Simple.localLookup(); 129 testOnMembersNoLookup("testPublicLookupNegative/1", mems, pubLookup); 130 testOnMembersNoReveal("testPublicLookupNegative/2", mems, privLookup, pubLookup); 131 testOnMembersNoReflect("testPublicLookupNegative/3", mems, privLookup, pubLookup); 132 } 133 @Test public void testJavaLangClass() throws Throwable { 134 if (VERBOSE) System.out.println("@Test testJavaLangClass"); 135 List<Member> mems = callerSensitive(false, publicOnly(getMembers(Class.class))); 136 mems = limit(20, mems); 137 testOnMembers("testJavaLangClass", mems, Simple.localLookup()); 138 } 139 @Test public void testCallerSensitive() throws Throwable { 140 if (VERBOSE) System.out.println("@Test testCallerSensitive"); 141 List<Member> mems = union(getMembers(MethodHandles.class, "lookup"), 142 getMembers(Method.class, "invoke"), 143 getMembers(Field.class, "get", "set", "getLong"), 144 getMembers(Class.class)); 145 mems = callerSensitive(true, publicOnly(mems)); 146 mems = limit(10, mems); 147 testOnMembers("testCallerSensitive", mems, Simple.localLookup()); 148 } 149 @Test public void testCallerSensitiveNegative() throws Throwable { 150 if (VERBOSE) System.out.println("@Test testCallerSensitiveNegative"); 151 List<Member> mems = union(getMembers(MethodHandles.class, "lookup"), 152 getMembers(Class.class, "forName"), 153 getMembers(Method.class, "invoke")); 154 mems = callerSensitive(true, publicOnly(mems)); 155 // CS methods cannot be looked up with publicLookup 156 testOnMembersNoLookup("testCallerSensitiveNegative/1", mems, publicLookup()); 157 // CS methods have to be revealed with a matching lookupClass 158 testOnMembersNoReveal("testCallerSensitiveNegative/2", mems, Simple.localLookup(), publicLookup()); 159 testOnMembersNoReveal("testCallerSensitiveNegative/3", mems, Simple.localLookup(), Nestmate.localLookup()); 160 } 161 @Test public void testMethodHandleNatives() throws Throwable { 162 if (VERBOSE) System.out.println("@Test testMethodHandleNatives"); 163 List<Member> mems = getMembers(MethodHandle.class, "invoke", "invokeExact"); 164 testOnMembers("testMethodHandleNatives", mems, Simple.localLookup()); 165 } 166 @Test public void testMethodHandleInvokes() throws Throwable { 167 if (VERBOSE) System.out.println("@Test testMethodHandleInvokes"); 168 List<MethodType> types = new ArrayList<>(); 169 Class<?>[] someParamTypes = { void.class, int.class, Object.class, Object[].class }; 170 for (Class<?> rt : someParamTypes) { 171 for (Class<?> p0 : someParamTypes) { 172 if (p0 == void.class) { types.add(methodType(rt)); continue; } 173 for (Class<?> p1 : someParamTypes) { 174 if (p1 == void.class) { types.add(methodType(rt, p0)); continue; } 175 for (Class<?> p2 : someParamTypes) { 176 if (p2 == void.class) { types.add(methodType(rt, p0, p1)); continue; } 177 types.add(methodType(rt, p0, p1, p2)); 178 } 179 } 180 } 181 } 182 List<Member> mems = union(getPolyMembers(MethodHandle.class, "invoke", types), 183 getPolyMembers(MethodHandle.class, "invokeExact", types)); 184 testOnMembers("testMethodHandleInvokes/1", mems, Simple.localLookup()); 185 testOnMembers("testMethodHandleInvokes/2", mems, publicLookup()); 186 } 187 188 static List<Member> getPolyMembers(Class<?> cls, String name, List<MethodType> types) { 189 assert(cls == MethodHandle.class); 190 ArrayList<Member> mems = new ArrayList<>(); 191 for (MethodType type : types) { 192 mems.add(new SignaturePolymorphicMethod(name, type)); 193 } 194 return mems; 195 } 196 static List<Member> getMembers(Class<?> cls) { 197 return getMembers(cls, (String[]) null); 198 } 199 static List<Member> getMembers(Class<?> cls, String... onlyNames) { 200 List<String> names = (onlyNames == null || onlyNames.length == 0 ? null : Arrays.asList(onlyNames)); 201 ArrayList<Member> res = new ArrayList<>(); 202 for (Class<?> sup : getSupers(cls)) { 203 res.addAll(getDeclaredMembers(sup, "getDeclaredFields")); 204 res.addAll(getDeclaredMembers(sup, "getDeclaredMethods")); 205 res.addAll(getDeclaredMembers(sup, "getDeclaredConstructors")); 206 } 207 res = new ArrayList<>(new LinkedHashSet<>(res)); 208 for (int i = 0; i < res.size(); i++) { 209 Member mem = res.get(i); 210 if (!canBeReached(mem, cls) || 211 res.indexOf(mem) != i || 212 mem.isSynthetic() || 213 (names != null && !names.contains(mem.getName())) 214 ) { 215 res.remove(i--); 216 } 217 } 218 return res; 219 } 220 static List<Class<?>> getSupers(Class<?> cls) { 221 ArrayList<Class<?>> res = new ArrayList<>(); 222 ArrayList<Class<?>> intfs = new ArrayList<>(); 223 for (Class<?> sup = cls; sup != null; sup = sup.getSuperclass()) { 224 res.add(sup); 225 for (Class<?> intf : cls.getInterfaces()) { 226 if (!intfs.contains(intf)) 227 intfs.add(intf); 228 } 229 } 230 for (int i = 0; i < intfs.size(); i++) { 231 for (Class<?> intf : intfs.get(i).getInterfaces()) { 232 if (!intfs.contains(intf)) 233 intfs.add(intf); 234 } 235 } 236 res.addAll(intfs); 237 //System.out.println("getSupers => "+res); 238 return res; 239 } 240 static boolean hasSM() { 241 return (System.getSecurityManager() != null); 242 } 243 static List<Member> getDeclaredMembers(Class<?> cls, String accessor) { 244 Member[] mems = {}; 245 Method getter = getMethod(Class.class, accessor); 246 if (hasSM()) { 247 try { 248 mems = (Member[]) invokeMethod(getter, cls); 249 } catch (SecurityException ex) { 250 //if (VERBOSE) ex.printStackTrace(); 251 accessor = accessor.replace("Declared", ""); 252 getter = getMethod(Class.class, accessor); 253 if (VERBOSE) System.out.println("replaced accessor: "+getter); 254 } 255 } 256 if (mems.length == 0) { 257 try { 258 mems = (Member[]) invokeMethod(getter, cls); 259 } catch (SecurityException ex) { 260 ex.printStackTrace(); 261 } 262 } 263 if (VERBOSE) System.out.println(accessor+" "+cls.getName()+" => "+mems.length+" members"); 264 return Arrays.asList(mems); 265 } 266 static Method getMethod(Class<?> cls, String name) { 267 try { 268 return cls.getMethod(name); 269 } catch (ReflectiveOperationException ex) { 270 throw new AssertionError(ex); 271 } 272 } 273 static Object invokeMethod(Method m, Object recv, Object... args) { 274 try { 275 return m.invoke(recv, args); 276 } catch (InvocationTargetException ex) { 277 Throwable ex2 = ex.getCause(); 278 if (ex2 instanceof RuntimeException) throw (RuntimeException) ex2; 279 if (ex2 instanceof Error) throw (Error) ex2; 280 throw new AssertionError(ex); 281 } catch (ReflectiveOperationException ex) { 282 throw new AssertionError(ex); 283 } 284 } 285 286 static List<Member> limit(int len, List<Member> mems) { 287 if (mems.size() <= len) return mems; 288 return mems.subList(0, len); 289 } 290 @SafeVarargs 291 static List<Member> union(List<Member> mems, List<Member>... mem2s) { 292 for (List<Member> mem2 : mem2s) { 293 for (Member m : mem2) { 294 if (!mems.contains(m)) 295 mems.add(m); 296 } 297 } 298 return mems; 299 } 300 static List<Member> callerSensitive(boolean cond, List<Member> members) { 301 for (Iterator<Member> i = members.iterator(); i.hasNext(); ) { 302 Member mem = i.next(); 303 if (isCallerSensitive(mem) != cond) 304 i.remove(); 305 } 306 if (members.isEmpty()) throw new AssertionError("trivial result"); 307 return members; 308 } 309 static boolean isCallerSensitive(Member mem) { 310 if (!(mem instanceof AnnotatedElement)) return false; 311 AnnotatedElement ae = (AnnotatedElement) mem; 312 if (CS_CLASS != null) 313 return ae.isAnnotationPresent(sun.reflect.CallerSensitive.class); 314 for (java.lang.annotation.Annotation a : ae.getDeclaredAnnotations()) { 315 if (a.toString().contains(".CallerSensitive")) 316 return true; 317 } 318 return false; 319 } 320 static final Class<?> CS_CLASS; 321 static { 322 Class<?> c = null; 323 try { 324 c = sun.reflect.CallerSensitive.class; 325 } catch (SecurityException | LinkageError ex) { 326 } 327 CS_CLASS = c; 328 } 329 static List<Member> publicOnly(List<Member> members) { 330 return removeMods(members, Modifier.PUBLIC, 0); 331 } 332 static List<Member> nonPublicOnly(List<Member> members) { 333 return removeMods(members, Modifier.PUBLIC, -1); 334 } 335 static List<Member> removeMods(List<Member> members, int mask, int bits) { 336 int publicMods = (mask & Modifier.PUBLIC); 337 members = new ArrayList<>(members); 338 for (Iterator<Member> i = members.iterator(); i.hasNext(); ) { 339 Member mem = i.next(); 340 int mods = mem.getModifiers(); 341 if ((publicMods & mods) != 0 && 342 (publicMods & mem.getDeclaringClass().getModifiers()) == 0) 343 mods -= publicMods; 344 if ((mods & mask) == (bits & mask)) 345 i.remove(); 346 } 347 return members; 348 } 349 350 void testOnMembers(String tname, List<Member> mems, Lookup lookup, Lookup... lookups) throws Throwable { 351 if (VERBOSE) System.out.println("testOnMembers "+mems); 352 Lookup revLookup = (lookups.length > 0) ? lookups[0] : null; 353 if (revLookup == null) revLookup = lookup; 354 Lookup refLookup = (lookups.length > 1) ? lookups[1] : null; 355 if (refLookup == null) refLookup = lookup; 356 assert(lookups.length <= 2); 357 testOnMembersImpl(tname, mems, lookup, revLookup, refLookup, NO_FAIL); 358 } 359 void testOnMembersNoLookup(String tname, List<Member> mems, Lookup lookup) throws Throwable { 360 if (VERBOSE) System.out.println("testOnMembersNoLookup "+mems); 361 testOnMembersImpl(tname, mems, lookup, null, null, FAIL_LOOKUP); 362 } 363 void testOnMembersNoReveal(String tname, List<Member> mems, 364 Lookup lookup, Lookup negLookup) throws Throwable { 365 if (VERBOSE) System.out.println("testOnMembersNoReveal "+mems); 366 testOnMembersImpl(tname, mems, lookup, negLookup, null, FAIL_REVEAL); 367 } 368 void testOnMembersNoReflect(String tname, List<Member> mems, 369 Lookup lookup, Lookup negLookup) throws Throwable { 370 if (VERBOSE) System.out.println("testOnMembersNoReflect "+mems); 371 testOnMembersImpl(tname, mems, lookup, lookup, negLookup, FAIL_REFLECT); 372 } 373 void testOnMembersImpl(String tname, List<Member> mems, 374 Lookup lookup, 375 Lookup revLookup, 376 Lookup refLookup, 377 int failureMode) throws Throwable { 378 Throwable fail = null; 379 int failCount = 0; 380 failureModeCounts = new int[FAIL_MODE_COUNT]; 381 long tm0 = System.currentTimeMillis(); 382 for (Member mem : mems) { 383 try { 384 testWithMember(mem, lookup, revLookup, refLookup, failureMode); 385 } catch (Throwable ex) { 386 if (fail == null) fail = ex; 387 if (++failCount > 10) { System.out.println("*** FAIL: too many failures"); break; } 388 System.out.println("*** FAIL: "+mem+" => "+ex); 389 if (VERBOSE) ex.printStackTrace(System.out); 390 } 391 } 392 long tm1 = System.currentTimeMillis(); 393 System.out.printf("@Test %s executed %s tests in %d ms", 394 tname, testKinds(failureModeCounts), (tm1-tm0)).println(); 395 if (fail != null) throw fail; 396 } 397 static String testKinds(int[] modes) { 398 int pos = modes[0], neg = -pos; 399 for (int n : modes) neg += n; 400 if (neg == 0) return pos + " positive"; 401 String negs = ""; 402 for (int n : modes) negs += "/"+n; 403 negs = negs.replaceFirst("/"+pos+"/", ""); 404 negs += " negative"; 405 if (pos == 0) return negs; 406 return pos + " positive, " + negs; 407 } 408 static class SignaturePolymorphicMethod implements Member { // non-reflected instance of MH.invoke* 409 final String name; 410 final MethodType type; 411 SignaturePolymorphicMethod(String name, MethodType type) { 412 this.name = name; 413 this.type = type; 414 } 415 public String toString() { 416 String typeStr = type.toString(); 417 if (isVarArgs()) typeStr = typeStr.replaceFirst("\\[\\])$", "...)"); 418 return (Modifier.toString(getModifiers()) 419 +typeStr.substring(0, typeStr.indexOf('('))+" " 420 +getDeclaringClass().getTypeName()+"." 421 +getName()+typeStr.substring(typeStr.indexOf('('))); 422 } 423 public boolean equals(Object x) { 424 return (x instanceof SignaturePolymorphicMethod && equals((SignaturePolymorphicMethod)x)); 425 } 426 public boolean equals(SignaturePolymorphicMethod that) { 427 return this.name.equals(that.name) && this.type.equals(that.type); 428 } 429 public int hashCode() { 430 return name.hashCode() * 31 + type.hashCode(); 431 } 432 public Class<?> getDeclaringClass() { return MethodHandle.class; } 433 public String getName() { return name; } 434 public MethodType getMethodType() { return type; } 435 public int getModifiers() { return Modifier.PUBLIC | Modifier.FINAL | Modifier.NATIVE | SYNTHETIC; } 436 public boolean isVarArgs() { return Modifier.isTransient(getModifiers()); } 437 public boolean isSynthetic() { return true; } 438 public Class<?> getReturnType() { return type.returnType(); } 439 public Class<?>[] getParameterTypes() { return type.parameterArray(); } 440 static final int SYNTHETIC = 0x00001000; 441 } 442 static class UnreflectResult { // a tuple 443 final MethodHandle mh; 444 final Throwable ex; 445 final byte kind; 446 final Member mem; 447 final int var; 448 UnreflectResult(MethodHandle mh, byte kind, Member mem, int var) { 449 this.mh = mh; 450 this.ex = null; 451 this.kind = kind; 452 this.mem = mem; 453 this.var = var; 454 } 455 UnreflectResult(Throwable ex, byte kind, Member mem, int var) { 456 this.mh = null; 457 this.ex = ex; 458 this.kind = kind; 459 this.mem = mem; 460 this.var = var; 461 } 462 public String toString() { 463 return toInfoString()+"/v"+var; 464 } 465 public String toInfoString() { 466 return String.format("%s %s.%s:%s", MethodHandleInfo.referenceKindToString(kind), 467 mem.getDeclaringClass().getName(), name(mem), type(mem, kind)); 468 } 469 static String name(Member mem) { 470 if (mem instanceof Constructor) return "<init>"; 471 return mem.getName(); 472 } 473 static MethodType type(Member mem, byte kind) { 474 if (mem instanceof Field) { 475 Class<?> type = ((Field)mem).getType(); 476 if (kind == REF_putStatic || kind == REF_putField) 477 return methodType(void.class, type); 478 return methodType(type); 479 } else if (mem instanceof SignaturePolymorphicMethod) { 480 return ((SignaturePolymorphicMethod)mem).getMethodType(); 481 } 482 Class<?>[] params = ((Executable)mem).getParameterTypes(); 483 if (mem instanceof Constructor) 484 return methodType(void.class, params); 485 Class<?> type = ((Method)mem).getReturnType(); 486 return methodType(type, params); 487 } 488 } 489 static UnreflectResult unreflectMember(Lookup lookup, Member mem, int variation) { 490 byte[] refKind = {0}; 491 try { 492 return unreflectMemberOrThrow(lookup, mem, variation, refKind); 493 } catch (ReflectiveOperationException|SecurityException ex) { 494 return new UnreflectResult(ex, refKind[0], mem, variation); 495 } 496 } 497 static UnreflectResult unreflectMemberOrThrow(Lookup lookup, Member mem, int variation, 498 byte[] refKind) throws ReflectiveOperationException { 499 Class<?> cls = lookup.lookupClass(); 500 Class<?> defc = mem.getDeclaringClass(); 501 String name = mem.getName(); 502 int mods = mem.getModifiers(); 503 boolean isStatic = Modifier.isStatic(mods); 504 MethodHandle mh = null; 505 byte kind = 0; 506 if (mem instanceof Method) { 507 Method m = (Method) mem; 508 MethodType type = methodType(m.getReturnType(), m.getParameterTypes()); 509 boolean canBeSpecial = (!isStatic && 510 (lookup.lookupModes() & Modifier.PRIVATE) != 0 && 511 defc.isAssignableFrom(cls) && 512 (!defc.isInterface() || Arrays.asList(cls.getInterfaces()).contains(defc))); 513 if (variation >= 2) 514 kind = REF_invokeSpecial; 515 else if (isStatic) 516 kind = REF_invokeStatic; 517 else if (defc.isInterface()) 518 kind = REF_invokeInterface; 519 else 520 kind = REF_invokeVirtual; 521 refKind[0] = kind; 522 switch (variation) { 523 case 0: 524 mh = lookup.unreflect(m); 525 break; 526 case 1: 527 if (defc == MethodHandle.class && 528 !isStatic && 529 m.isVarArgs() && 530 Modifier.isFinal(mods) && 531 Modifier.isNative(mods)) { 532 break; 533 } 534 if (isStatic) 535 mh = lookup.findStatic(defc, name, type); 536 else 537 mh = lookup.findVirtual(defc, name, type); 538 break; 539 case 2: 540 if (!canBeSpecial) 541 break; 542 mh = lookup.unreflectSpecial(m, lookup.lookupClass()); 543 break; 544 case 3: 545 if (!canBeSpecial) 546 break; 547 mh = lookup.findSpecial(defc, name, type, lookup.lookupClass()); 548 break; 549 } 550 } else if (mem instanceof SignaturePolymorphicMethod) { 551 SignaturePolymorphicMethod m = (SignaturePolymorphicMethod) mem; 552 MethodType type = methodType(m.getReturnType(), m.getParameterTypes()); 553 kind = REF_invokeVirtual; 554 refKind[0] = kind; 555 switch (variation) { 556 case 0: 557 mh = lookup.findVirtual(defc, name, type); 558 break; 559 } 560 } else if (mem instanceof Constructor) { 561 name = "<init>"; // not used 562 Constructor<?> m = (Constructor<?>) mem; 563 MethodType type = methodType(void.class, m.getParameterTypes()); 564 kind = REF_newInvokeSpecial; 565 refKind[0] = kind; 566 switch (variation) { 567 case 0: 568 mh = lookup.unreflectConstructor(m); 569 break; 570 case 1: 571 mh = lookup.findConstructor(defc, type); 572 break; 573 } 574 } else if (mem instanceof Field) { 575 Field m = (Field) mem; 576 Class<?> type = m.getType(); 577 boolean canHaveSetter = !Modifier.isFinal(mods); 578 if (variation >= 2) 579 kind = (byte)(isStatic ? REF_putStatic : REF_putField); 580 else 581 kind = (byte)(isStatic ? REF_getStatic : REF_getField); 582 refKind[0] = kind; 583 switch (variation) { 584 case 0: 585 mh = lookup.unreflectGetter(m); 586 break; 587 case 1: 588 if (isStatic) 589 mh = lookup.findStaticGetter(defc, name, type); 590 else 591 mh = lookup.findGetter(defc, name, type); 592 break; 593 case 3: 594 if (!canHaveSetter) 595 break; 596 mh = lookup.unreflectSetter(m); 597 break; 598 case 2: 599 if (!canHaveSetter) 600 break; 601 if (isStatic) 602 mh = lookup.findStaticSetter(defc, name, type); 603 else 604 mh = lookup.findSetter(defc, name, type); 605 break; 606 } 607 } else { 608 throw new IllegalArgumentException(String.valueOf(mem)); 609 } 610 if (mh == null) 611 // ran out of valid variations; return null to caller 612 return null; 613 return new UnreflectResult(mh, kind, mem, variation); 614 } 615 static boolean canBeReached(Member mem, Class<?> cls) { 616 Class<?> defc = mem.getDeclaringClass(); 617 String name = mem.getName(); 618 int mods = mem.getModifiers(); 619 if (mem instanceof Constructor) { 620 name = "<init>"; // according to 292 spec. 621 } 622 if (defc == cls) 623 return true; 624 if (name.startsWith("<")) 625 return false; // only my own constructors 626 if (Modifier.isPrivate(mods)) 627 return false; // only my own constructors 628 if (defc.getPackage() == cls.getPackage()) 629 return true; // package access or greater OK 630 if (Modifier.isPublic(mods)) 631 return true; // publics always OK 632 if (Modifier.isProtected(mods) && defc.isAssignableFrom(cls)) 633 return true; // protected OK 634 return false; 635 } 636 static boolean consistent(UnreflectResult res, MethodHandleInfo info) { 637 assert(res.mh != null); 638 assertEquals(res.kind, info.getReferenceKind()); 639 assertEquals(res.mem.getModifiers(), info.getModifiers()); 640 assertEquals(res.mem.getDeclaringClass(), info.getDeclaringClass()); 641 String expectName = res.mem.getName(); 642 if (res.kind == REF_newInvokeSpecial) 643 expectName = "<init>"; 644 assertEquals(expectName, info.getName()); 645 MethodType expectType = res.mh.type(); 646 if ((res.kind & 1) == (REF_getField & 1)) 647 expectType = expectType.dropParameterTypes(0, 1); 648 if (res.kind == REF_newInvokeSpecial) 649 expectType = expectType.changeReturnType(void.class); 650 assertEquals(expectType, info.getMethodType()); 651 assertEquals(res.mh.isVarargsCollector(), isVarArgs(info)); 652 assertEquals(res.toInfoString(), info.toString()); 653 assertEquals(res.toInfoString(), MethodHandleInfo.toString(info.getReferenceKind(), info.getDeclaringClass(), info.getName(), info.getMethodType())); 654 return true; 655 } 656 static boolean isVarArgs(MethodHandleInfo info) { 657 return info.isVarArgs(); 658 } 659 static boolean consistent(Member mem, Member mem2) { 660 assertEquals(mem, mem2); 661 return true; 662 } 663 static boolean consistent(MethodHandleInfo info, MethodHandleInfo info2) { 664 assertEquals(info.getReferenceKind(), info2.getReferenceKind()); 665 assertEquals(info.getModifiers(), info2.getModifiers()); 666 assertEquals(info.getDeclaringClass(), info2.getDeclaringClass()); 667 assertEquals(info.getName(), info2.getName()); 668 assertEquals(info.getMethodType(), info2.getMethodType()); 669 assertEquals(isVarArgs(info), isVarArgs(info)); 670 return true; 671 } 672 static boolean consistent(MethodHandle mh, MethodHandle mh2) { 673 assertEquals(mh.type(), mh2.type()); 674 assertEquals(mh.isVarargsCollector(), mh2.isVarargsCollector()); 675 return true; 676 } 677 int[] failureModeCounts; 678 static final int NO_FAIL=0, FAIL_LOOKUP=1, FAIL_REVEAL=2, FAIL_REFLECT=3, FAIL_MODE_COUNT=4; 679 void testWithMember(Member mem, 680 Lookup lookup, // initial lookup of member => MH 681 Lookup revLookup, // reveal MH => info 682 Lookup refLookup, // reflect info => member 683 int failureMode) throws Throwable { 684 boolean expectEx1 = (failureMode == FAIL_LOOKUP); // testOnMembersNoLookup 685 boolean expectEx2 = (failureMode == FAIL_REVEAL); // testOnMembersNoReveal 686 boolean expectEx3 = (failureMode == FAIL_REFLECT); // testOnMembersNoReflect 687 for (int variation = 0; ; variation++) { 688 UnreflectResult res = unreflectMember(lookup, mem, variation); 689 failureModeCounts[failureMode] += 1; 690 if (variation == 0) assert(res != null); 691 if (res == null) break; 692 if (VERBOSE && variation == 0) 693 System.out.println("from "+mem.getDeclaringClass().getSimpleName()); 694 MethodHandle mh = res.mh; 695 Throwable ex1 = res.ex; 696 if (VERBOSE) System.out.println(" "+variation+": "+res+" << "+(mh != null ? mh : ex1)); 697 if (expectEx1 && ex1 != null) 698 continue; // this is OK; we expected that lookup to fail 699 if (expectEx1) 700 throw new AssertionError("unexpected lookup for negative test"); 701 if (ex1 != null && !expectEx1) { 702 if (failureMode != NO_FAIL) 703 throw new AssertionError("unexpected lookup failure for negative test", ex1); 704 throw ex1; 705 } 706 MethodHandleInfo info; 707 try { 708 info = revLookup.revealDirect(mh); 709 if (expectEx2) throw new AssertionError("unexpected revelation for negative test"); 710 } catch (IllegalArgumentException|SecurityException ex2) { 711 if (VERBOSE) System.out.println(" "+variation+": "+res+" => "+mh.getClass().getName()+" => (EX2)"+ex2); 712 if (expectEx2) 713 continue; // this is OK; we expected the reflect to fail 714 if (failureMode != NO_FAIL) 715 throw new AssertionError("unexpected revelation failure for negative test", ex2); 716 throw ex2; 717 } 718 assert(consistent(res, info)); 719 Member mem2; 720 try { 721 mem2 = info.reflectAs(Member.class, refLookup); 722 if (expectEx3) throw new AssertionError("unexpected reflection for negative test"); 723 assert(!(mem instanceof SignaturePolymorphicMethod)); 724 } catch (IllegalArgumentException ex3) { 725 if (VERBOSE) System.out.println(" "+variation+": "+info+" => (EX3)"+ex3); 726 if (expectEx3) 727 continue; // this is OK; we expected the reflect to fail 728 if (mem instanceof SignaturePolymorphicMethod) 729 continue; // this is OK; we cannot reflect MH.invokeExact(a,b,c) 730 if (failureMode != NO_FAIL) 731 throw new AssertionError("unexpected reflection failure for negative test", ex3); 732 throw ex3; 733 } 734 assert(consistent(mem, mem2)); 735 UnreflectResult res2 = unreflectMember(lookup, mem2, variation); 736 MethodHandle mh2 = res2.mh; 737 assert(consistent(mh, mh2)); 738 MethodHandleInfo info2 = lookup.revealDirect(mh2); 739 assert(consistent(info, info2)); 740 assert(consistent(res, info2)); 741 Member mem3; 742 if (hasSM()) 743 mem3 = info2.reflectAs(Member.class, lookup); 744 else 745 mem3 = MethodHandles.reflectAs(Member.class, mh2); 746 assert(consistent(mem2, mem3)); 747 if (hasSM()) { 748 try { 749 MethodHandles.reflectAs(Member.class, mh2); 750 throw new AssertionError("failed to throw on "+mem3); 751 } catch (SecurityException ex3) { 752 // OK... 753 } 754 } 755 } 756 } 757} 758