/* * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions.
*/
/* * @test * @summary verify Lookup.revealDirect on a variety of input handles * @modules java.base/jdk.internal.reflect * @compile -XDignore.symbol.file RevealDirectTest.java * @run junit/othervm -ea -esa test.java.lang.invoke.RevealDirectTest * * @test * @summary verify Lookup.revealDirect on a variety of input handles, with security manager * @run main/othervm/policy=jtreg.security.policy/secure=java.lang.SecurityManager -ea -esa test.java.lang.invoke.RevealDirectTest
*/
publicclass RevealDirectTest { publicstaticvoid main(String... av) throws Throwable { // Run the @Test methods explicitly, in case we don't want to use the JUnitCore driver. // This appears to be necessary when running with a security manager.
Throwable fail = null; for (Method test : RevealDirectTest.class.getDeclaredMethods()) { if (!test.isAnnotationPresent(Test.class)) continue; try {
test.invoke(new RevealDirectTest());
} catch (Throwable ex) { if (ex instanceof InvocationTargetException)
ex = ex.getCause(); if (fail == null) fail = ex;
System.out.println("Testcase: "+test.getName()
+"("+test.getDeclaringClass().getName()
+"):\tCaused an ERROR");
System.out.println(ex);
ex.printStackTrace(System.out);
}
} if (fail != null) throw fail;
}
static List<Member> limit(int len, List<Member> mems) { if (mems.size() <= len) return mems; return mems.subList(0, len);
}
@SafeVarargs static List<Member> union(List<Member> mems, List<Member>... mem2s) { for (List<Member> mem2 : mem2s) { for (Member m : mem2) { if (!mems.contains(m))
mems.add(m);
}
} return mems;
} static List<Member> callerSensitive(boolean cond, List<Member> members) { for (Iterator<Member> i = members.iterator(); i.hasNext(); ) {
Member mem = i.next(); if (isCallerSensitive(mem) != cond)
i.remove();
} if (members.isEmpty()) thrownew AssertionError("trivial result"); return members;
} staticboolean isCallerSensitive(Member mem) { if (!(mem instanceof AnnotatedElement)) returnfalse;
AnnotatedElement ae = (AnnotatedElement) mem; if (CS_CLASS != null) return ae.isAnnotationPresent(jdk.internal.reflect.CallerSensitive.class); for (java.lang.annotation.Annotation a : ae.getDeclaredAnnotations()) { if (a.toString().contains(".CallerSensitive")) returntrue;
} returnfalse;
} staticfinalClass<?> CS_CLASS; static { Class<?> c = null; try {
c = jdk.internal.reflect.CallerSensitive.class;
} catch (SecurityException | LinkageError ex) {
}
CS_CLASS = c;
} static List<Member> publicOnly(List<Member> members) { return removeMods(members, Modifier.PUBLIC, 0);
} static List<Member> nonPublicOnly(List<Member> members) { return removeMods(members, Modifier.PUBLIC, -1);
} static List<Member> removeMods(List<Member> members, int mask, int bits) { int publicMods = (mask & Modifier.PUBLIC);
members = new ArrayList<>(members); for (Iterator<Member> i = members.iterator(); i.hasNext(); ) {
Member mem = i.next(); int mods = mem.getModifiers(); if ((publicMods & mods) != 0 &&
(publicMods & mem.getDeclaringClass().getModifiers()) == 0)
mods -= publicMods; if ((mods & mask) == (bits & mask))
i.remove();
} return members;
}
void testOnMembers(String tname, List<Member> mems, Lookup lookup, Lookup... lookups) throws Throwable { if (VERBOSE) System.out.println("testOnMembers "+mems);
Lookup revLookup = (lookups.length > 0) ? lookups[0] : null; if (revLookup == null) revLookup = lookup;
Lookup refLookup = (lookups.length > 1) ? lookups[1] : null; if (refLookup == null) refLookup = lookup; assert(lookups.length <= 2);
testOnMembersImpl(tname, mems, lookup, revLookup, refLookup, NO_FAIL);
} void testOnMembersNoLookup(String tname, List<Member> mems, Lookup lookup) throws Throwable { if (VERBOSE) System.out.println("testOnMembersNoLookup "+mems);
testOnMembersImpl(tname, mems, lookup, null, null, FAIL_LOOKUP);
} void testOnMembersNoReveal(String tname, List<Member> mems,
Lookup lookup, Lookup negLookup) throws Throwable { if (VERBOSE) System.out.println("testOnMembersNoReveal "+mems);
testOnMembersImpl(tname, mems, lookup, negLookup, null, FAIL_REVEAL);
} void testOnMembersNoReflect(String tname, List<Member> mems,
Lookup lookup, Lookup negLookup) throws Throwable { if (VERBOSE) System.out.println("testOnMembersNoReflect "+mems);
testOnMembersImpl(tname, mems, lookup, lookup, negLookup, FAIL_REFLECT);
} void testOnMembersImpl(String tname, List<Member> mems,
Lookup lookup,
Lookup revLookup,
Lookup refLookup, int failureMode) throws Throwable {
Throwable fail = null; int failCount = 0;
failureModeCounts = newint[FAIL_MODE_COUNT]; long tm0 = System.currentTimeMillis(); for (Member mem : mems) { try {
testWithMember(mem, lookup, revLookup, refLookup, failureMode);
} catch (Throwable ex) { if (fail == null) fail = ex; if (++failCount > 10) { System.out.println("*** FAIL: too many failures"); break; }
System.out.println("*** FAIL: "+mem+" => "+ex); if (VERBOSE) ex.printStackTrace(System.out);
}
} long tm1 = System.currentTimeMillis();
System.out.printf("@Test %s executed %s tests in %d ms",
tname, testKinds(failureModeCounts), (tm1-tm0)).println(); if (fail != null) throw fail;
} static String testKinds(int[] modes) { int pos = modes[0], neg = -pos; for (int n : modes) neg += n; if (neg == 0) return pos + " positive";
String negs = ""; for (int n : modes) negs += "/"+n;
negs = negs.replaceFirst("/"+pos+"/", "");
negs += " negative"; if (pos == 0) return negs; return pos + " positive, " + negs;
} staticclass SignaturePolymorphicMethod implements Member { // non-reflected instance of MH.invoke* final String name; final MethodType type;
SignaturePolymorphicMethod(String name, MethodType type) { this.name = name; this.type = type;
} public String toString() {
String typeStr = type.toString(); if (isVarArgs()) typeStr = typeStr.replaceFirst("\\[\\])$", "...)"); return (Modifier.toString(getModifiers())
+typeStr.substring(0, typeStr.indexOf('('))+" "
+getDeclaringClass().getTypeName()+"."
+getName()+typeStr.substring(typeStr.indexOf('(')));
} publicboolean equals(Object x) { return (x instanceof SignaturePolymorphicMethod && equals((SignaturePolymorphicMethod)x));
} publicboolean equals(SignaturePolymorphicMethod that) { returnthis.name.equals(that.name) && this.type.equals(that.type);
} publicint hashCode() { return name.hashCode() * 31 + type.hashCode();
} publicClass<?> getDeclaringClass() { return MethodHandle.class; } public String getName() { return name; } public MethodType getMethodType() { return type; } publicint getModifiers() { return Modifier.PUBLIC | Modifier.FINAL | Modifier.NATIVE | SYNTHETIC; } publicboolean isVarArgs() { return Modifier.isTransient(getModifiers()); } publicboolean isSynthetic() { returntrue; } publicClass<?> getReturnType() { return type.returnType(); } publicClass<?>[] getParameterTypes() { return type.parameterArray(); } staticfinalint SYNTHETIC = 0x00001000;
} staticclass UnreflectResult { // a tuple final MethodHandle mh; final Throwable ex; finalbyte kind; final Member mem; finalintvar;
UnreflectResult(MethodHandle mh, byte kind, Member mem, intvar) { this.mh = mh; this.ex = null; this.kind = kind; this.mem = mem; this.var = var;
}
UnreflectResult(Throwable ex, byte kind, Member mem, intvar) { this.mh = null; this.ex = ex; this.kind = kind; this.mem = mem; this.var = var;
} public String toString() { return toInfoString()+"/v"+var;
} public String toInfoString() { return String.format("%s %s.%s:%s", MethodHandleInfo.referenceKindToString(kind),
mem.getDeclaringClass().getName(), name(mem), type(mem, kind));
} static String name(Member mem) { if (mem instanceof Constructor) return""; return mem.getName();
} static MethodType type(Member mem, byte kind) { if (mem instanceof Field) { Class<?> type = ((Field)mem).getType(); if (kind == REF_putStatic || kind == REF_putField) return methodType(void.class, type); return methodType(type);
} elseif (mem instanceof SignaturePolymorphicMethod) { return ((SignaturePolymorphicMethod)mem).getMethodType();
} Class<?>[] params = ((Executable)mem).getParameterTypes(); if (mem instanceof Constructor) return methodType(void.class, params); Class<?> type = ((Method)mem).getReturnType(); return methodType(type, params);
}
} static UnreflectResult unreflectMember(Lookup lookup, Member mem, int variation) { byte[] refKind = {0}; try { return unreflectMemberOrThrow(lookup, mem, variation, refKind);
} catch (ReflectiveOperationException|SecurityException ex) { returnnew UnreflectResult(ex, refKind[0], mem, variation);
}
} static UnreflectResult unreflectMemberOrThrow(Lookup lookup, Member mem, int variation, byte[] refKind) throws ReflectiveOperationException { Class<?> cls = lookup.lookupClass(); Class<?> defc = mem.getDeclaringClass();
String name = mem.getName(); int mods = mem.getModifiers(); boolean isStatic = Modifier.isStatic(mods);
MethodHandle mh = null; byte kind = 0; if (mem instanceof Method) {
Method m = (Method) mem;
MethodType type = methodType(m.getReturnType(), m.getParameterTypes()); boolean canBeSpecial = (!isStatic &&
(lookup.lookupModes() & Modifier.PRIVATE) != 0 &&
defc.isAssignableFrom(cls) &&
(!defc.isInterface() || Arrays.asList(cls.getInterfaces()).contains(defc))); if (variation >= 2)
kind = REF_invokeSpecial; elseif (isStatic)
kind = REF_invokeStatic; elseif (defc.isInterface())
kind = REF_invokeInterface; else
kind = REF_invokeVirtual;
refKind[0] = kind; switch (variation) { case 0:
mh = lookup.unreflect(m); break; case 1: if (defc == MethodHandle.class &&
!isStatic &&
m.isVarArgs() &&
Modifier.isFinal(mods) &&
Modifier.isNative(mods)) { break;
} if (isStatic)
mh = lookup.findStatic(defc, name, type); else
mh = lookup.findVirtual(defc, name, type); break; case 2: if (!canBeSpecial) break;
mh = lookup.unreflectSpecial(m, lookup.lookupClass()); break; case 3: if (!canBeSpecial) break;
mh = lookup.findSpecial(defc, name, type, lookup.lookupClass()); break;
}
} elseif (mem instanceof SignaturePolymorphicMethod) {
SignaturePolymorphicMethod m = (SignaturePolymorphicMethod) mem;
MethodType type = methodType(m.getReturnType(), m.getParameterTypes());
kind = REF_invokeVirtual;
refKind[0] = kind; switch (variation) { case 0:
mh = lookup.findVirtual(defc, name, type); break;
}
} elseif (mem instanceof Constructor) {
name = ""; // not used
Constructor<?> m = (Constructor<?>) mem;
MethodType type = methodType(void.class, m.getParameterTypes());
kind = REF_newInvokeSpecial;
refKind[0] = kind; switch (variation) { case 0:
mh = lookup.unreflectConstructor(m); break; case 1:
mh = lookup.findConstructor(defc, type); break;
}
} elseif (mem instanceof Field) {
Field m = (Field) mem; Class<?> type = m.getType(); boolean canHaveSetter = !Modifier.isFinal(mods); if (variation >= 2)
kind = (byte)(isStatic ? REF_putStatic : REF_putField); else
kind = (byte)(isStatic ? REF_getStatic : REF_getField);
refKind[0] = kind; switch (variation) { case 0:
mh = lookup.unreflectGetter(m); break; case 1: if (isStatic)
mh = lookup.findStaticGetter(defc, name, type); else
mh = lookup.findGetter(defc, name, type); break; case 3: if (!canHaveSetter) break;
mh = lookup.unreflectSetter(m); break; case 2: if (!canHaveSetter) break; if (isStatic)
mh = lookup.findStaticSetter(defc, name, type); else
mh = lookup.findSetter(defc, name, type); break;
}
} else { thrownew IllegalArgumentException(String.valueOf(mem));
} if (mh == null) // ran out of valid variations; return null to caller returnnull; returnnew UnreflectResult(mh, kind, mem, variation);
} staticboolean canBeReached(Member mem, Class<?> cls) { Class<?> defc = mem.getDeclaringClass();
String name = mem.getName(); int mods = mem.getModifiers(); if (mem instanceof Constructor) {
name = ""; // according to 292 spec.
} if (defc == cls) returntrue; if (name.startsWith("<")) returnfalse; // only my own constructors if (Modifier.isPrivate(mods)) returnfalse; // only my own constructors if (defc.getPackage() == cls.getPackage()) returntrue; // package access or greater OK if (Modifier.isPublic(mods)) returntrue; // publics always OK if (Modifier.isProtected(mods) && defc.isAssignableFrom(cls)) returntrue; // protected OK returnfalse;
} staticboolean consistent(UnreflectResult res, MethodHandleInfo info) { assert(res.mh != null);
assertEquals(res.kind, info.getReferenceKind());
assertEquals(res.mem.getModifiers(), info.getModifiers());
assertEquals(res.mem.getDeclaringClass(), info.getDeclaringClass());
String expectName = res.mem.getName(); if (res.kind == REF_newInvokeSpecial)
expectName = "";
assertEquals(expectName, info.getName());
MethodType expectType = res.mh.type(); if ((res.kind & 1) == (REF_getField & 1))
expectType = expectType.dropParameterTypes(0, 1); if (res.kind == REF_newInvokeSpecial)
expectType = expectType.changeReturnType(void.class);
assertEquals(expectType, info.getMethodType());
assertEquals(res.mh.isVarargsCollector(), isVarArgs(info));
assertEquals(res.toInfoString(), info.toString());
assertEquals(res.toInfoString(), MethodHandleInfo.toString(info.getReferenceKind(), info.getDeclaringClass(), info.getName(), info.getMethodType())); returntrue;
} staticboolean isVarArgs(MethodHandleInfo info) { return info.isVarArgs();
} staticboolean consistent(Member mem, Member mem2) {
assertEquals(mem, mem2); returntrue;
} staticboolean consistent(MethodHandleInfo info, MethodHandleInfo info2) {
assertEquals(info.getReferenceKind(), info2.getReferenceKind());
assertEquals(info.getModifiers(), info2.getModifiers());
assertEquals(info.getDeclaringClass(), info2.getDeclaringClass());
assertEquals(info.getName(), info2.getName());
assertEquals(info.getMethodType(), info2.getMethodType());
assertEquals(isVarArgs(info), isVarArgs(info)); returntrue;
} staticboolean consistent(MethodHandle mh, MethodHandle mh2) {
assertEquals(mh.type(), mh2.type());
assertEquals(mh.isVarargsCollector(), mh2.isVarargsCollector()); returntrue;
} int[] failureModeCounts; staticfinalint NO_FAIL=0, FAIL_LOOKUP=1, FAIL_REVEAL=2, FAIL_REFLECT=3, FAIL_MODE_COUNT=4; void testWithMember(Member mem,
Lookup lookup, // initial lookup of member => MH
Lookup revLookup, // reveal MH => info
Lookup refLookup, // reflect info => member int failureMode) throws Throwable { boolean expectEx1 = (failureMode == FAIL_LOOKUP); // testOnMembersNoLookup boolean expectEx2 = (failureMode == FAIL_REVEAL); // testOnMembersNoReveal boolean expectEx3 = (failureMode == FAIL_REFLECT); // testOnMembersNoReflect for (int variation = 0; ; variation++) {
UnreflectResult res = unreflectMember(lookup, mem, variation);
failureModeCounts[failureMode] += 1; if (variation == 0) assert(res != null); if (res == null) break; if (VERBOSE && variation == 0)
System.out.println("from "+mem.getDeclaringClass().getSimpleName());
MethodHandle mh = res.mh;
Throwable ex1 = res.ex; if (VERBOSE) System.out.println(" "+variation+": "+res+" << "+(mh != null ? mh : ex1)); if (expectEx1 && ex1 != null) continue; // this is OK; we expected that lookup to fail if (expectEx1) thrownew AssertionError("unexpected lookup for negative test"); if (ex1 != null && !expectEx1) { if (failureMode != NO_FAIL) thrownew AssertionError("unexpected lookup failure for negative test", ex1); throw ex1;
}
MethodHandleInfo info; try {
info = revLookup.revealDirect(mh); if (expectEx2) thrownew AssertionError("unexpected revelation for negative test");
} catch (IllegalArgumentException|SecurityException ex2) { if (VERBOSE) System.out.println(" "+variation+": "+res+" => "+mh.getClass().getName()+" => (EX2)"+ex2); if (expectEx2) continue; // this is OK; we expected the reflect to fail if (failureMode != NO_FAIL) thrownew AssertionError("unexpected revelation failure for negative test", ex2); throw ex2;
} assert(consistent(res, info));
Member mem2; try {
mem2 = info.reflectAs(Member.class, refLookup); if (expectEx3) thrownew AssertionError("unexpected reflection for negative test"); assert(!(mem instanceof SignaturePolymorphicMethod));
} catch (IllegalArgumentException ex3) { if (VERBOSE) System.out.println(" "+variation+": "+info+" => (EX3)"+ex3); if (expectEx3) continue; // this is OK; we expected the reflect to fail if (mem instanceof SignaturePolymorphicMethod) continue; // this is OK; we cannot reflect MH.invokeExact(a,b,c) if (failureMode != NO_FAIL) thrownew AssertionError("unexpected reflection failure for negative test", ex3); throw ex3;
} assert(consistent(mem, mem2));
UnreflectResult res2 = unreflectMember(lookup, mem2, variation);
MethodHandle mh2 = res2.mh; assert(consistent(mh, mh2));
MethodHandleInfo info2 = lookup.revealDirect(mh2); assert(consistent(info, info2)); assert(consistent(res, info2));
Member mem3; if (hasSM())
mem3 = info2.reflectAs(Member.class, lookup); else
mem3 = MethodHandles.reflectAs(Member.class, mh2); assert(consistent(mem2, mem3)); if (hasSM()) { try {
MethodHandles.reflectAs(Member.class, mh2); thrownew AssertionError("failed to throw on "+mem3);
} catch (SecurityException ex3) { // OK...
}
}
}
}
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.22Bemerkung:
(vorverarbeitet)
¤