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