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