static MethodHandle[] makeLists() { ArrayList<MethodHandle> lists = new ArrayList<>(); MethodHandles.Lookup lookup = IMPL_LOOKUP; for (;;) { int nargs = lists.size(); MethodType type = MethodType.genericMethodType(nargs).changeReturnType(List.class); String name = "list"; MethodHandle list = null; try { list = lookup.findStatic(ValueConversions.class, name, type); } catch (ReflectiveOperationException ex) { // break from loop! } if (list == null) break; lists.add(list); } assertTrue(lists.size() == 11); // current number of methods return lists.toArray(new MethodHandle[0]); }
/** * Teleport from publicLookup to public type in unnamed module * * [A0] has PUBLIC access */ public void testPublicLookupToUnnamedModule() throws Exception { Lookup lookup = MethodHandles.publicLookup().in(unnamedClass); assertTrue(lookup.lookupModes() == PUBLIC); // A0 // m1 findConstructor(lookup, p1_Type1, void.class); findConstructorExpectingIAE(lookup, p2_Type2, void.class); // m2 findConstructor(lookup, q1_Type1, void.class); findConstructorExpectingIAE(lookup, q2_Type2, void.class); // java.base findConstructor(lookup, Object.class, void.class); findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); // unnamed findConstructor(lookup, unnamedClass, void.class); }
/** * Hop from publicLookup to accessible type in named module. * * [A0] has PUBLIC access */ public void testPublicLookupToAccessibleTypeInNamedModule() throws Exception { Lookup lookup = MethodHandles.publicLookup().in(p1_Type1); assertTrue(lookup.lookupModes() == PUBLIC); // A0 // m1 findConstructor(lookup, p1_Type1, void.class); findConstructorExpectingIAE(lookup, p2_Type2, void.class); // m2 findConstructor(lookup, q1_Type1, void.class); findConstructorExpectingIAE(lookup, q2_Type2, void.class); // java.base findConstructor(lookup, Object.class, void.class); findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); // unnamed findConstructor(lookup, unnamedClass, void.class); }
public void testGetter(int testMode) throws Throwable { Lookup lookup = PRIVATE; // FIXME: test more lookups than this one for (Object[] c : HasFields.CASES) { boolean positive = (c[1] != Error.class); testGetter(positive, lookup, c[0], c[1], testMode); if (positive) testGetter(positive, lookup, c[0], c[1], testMode | TEST_NPE); } testGetter(true, lookup, new Object[]{ true, System.class, "out", java.io.PrintStream.class }, System.out, testMode); for (int isStaticN = 0; isStaticN <= 1; isStaticN++) { testGetter(false, lookup, new Object[]{ (isStaticN != 0), System.class, "bogus", char.class }, null, testMode); } }
public static void main(String[] args) throws Throwable { Lookup LOOKUP = T3.lookup(); Class<IllegalAccessException> IAE = IllegalAccessException.class; assertFailure(IAE, () -> LOOKUP.findVirtual(T1.class, "m1", MethodType.methodType(void.class))); assertFailure(IAE, () -> LOOKUP.findStatic(T1.class, "m2", MethodType.methodType(void.class))); assertSuccess(() -> LOOKUP.findVirtual(T2.class, "m1", MethodType.methodType(void.class))); assertSuccess(() -> LOOKUP.findVirtual(T3.class, "m1", MethodType.methodType(void.class))); assertSuccess(() -> LOOKUP.findStatic(T2.class, "m2", MethodType.methodType(void.class))); assertSuccess(() -> LOOKUP.findStatic(T3.class, "m2", MethodType.methodType(void.class))); assertFailure(IAE, () -> LOOKUP.unreflect(T1.class.getDeclaredMethod("m1"))); assertFailure(IAE, () -> LOOKUP.unreflect(T1.class.getDeclaredMethod("m2"))); System.out.println("TEST PASSED"); }
public static void main(String[] args) throws Throwable { Lookup lookup = MethodHandles.lookup(); Method fooMethod = Foo.class.getDeclaredMethod("getName"); // fooMH2 displaces fooMH1 from the MemberNamesTable MethodHandle fooMH1 = lookup.unreflect(fooMethod); MethodHandle fooMH2 = lookup.unreflect(fooMethod); System.out.println("fooMH1.invoke = " + fooMH1.invokeExact()); System.out.println("fooMH2.invoke = " + fooMH2.invokeExact()); // Redefining Foo.getName() causes vmtarget to be updated // in fooMH2 but not fooMH1 redefineFoo(); // Full GC causes fooMH1.vmtarget to be deallocated System.gc(); // Calling fooMH1.vmtarget crashes the VM System.out.println("fooMH1.invoke = " + fooMH1.invokeExact()); }
private static MethodHandle generate(Lookup lookup, String className, MethodType mt, Recipe recipe) throws StringConcatException { try { switch (STRATEGY) { case BC_SB: return BytecodeStringBuilderStrategy.generate(lookup, className, mt, recipe, Mode.DEFAULT); case BC_SB_SIZED: return BytecodeStringBuilderStrategy.generate(lookup, className, mt, recipe, Mode.SIZED); case BC_SB_SIZED_EXACT: return BytecodeStringBuilderStrategy.generate(lookup, className, mt, recipe, Mode.SIZED_EXACT); case MH_SB_SIZED: return MethodHandleStringBuilderStrategy.generate(mt, recipe, Mode.SIZED); case MH_SB_SIZED_EXACT: return MethodHandleStringBuilderStrategy.generate(mt, recipe, Mode.SIZED_EXACT); case MH_INLINE_SIZED_EXACT: return MethodHandleInlineCopyStrategy.generate(mt, recipe); default: throw new StringConcatException("Concatenation strategy " + STRATEGY + " is not implemented"); } } catch (Error | StringConcatException e) { // Pass through any error or existing StringConcatException throw e; } catch (Throwable t) { throw new StringConcatException("Generator failed", t); } }
/** * Hop from publicLookup to accessible type in java.base */ public void testPublicLookupToBaseModule() throws Exception { Lookup lookup = MethodHandles.publicLookup().in(String.class); assertTrue(lookup.lookupModes() == PUBLIC); // A0 // m1 findConstructorExpectingIAE(lookup, p1_Type1, void.class); findConstructorExpectingIAE(lookup, p2_Type2, void.class); // m2 findConstructorExpectingIAE(lookup, q1_Type1, void.class); findConstructorExpectingIAE(lookup, q2_Type2, void.class); // java.base findConstructor(lookup, Object.class, void.class); findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); // unnamed findConstructorExpectingIAE(lookup, unnamedClass, void.class); }
public void testTargetClassInOpenModule() throws Throwable { // m1/p1.Type Class<?> clazz = Class.forName("p1.Type"); assertEquals(clazz.getModule().getName(), "m1"); // ensure that this module reads m1 Module thisModule = getClass().getModule(); Module m1 = clazz.getModule(); thisModule.addReads(clazz.getModule()); assertTrue(m1.isOpen("p1", thisModule)); Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup()); assertTrue(lookup.lookupClass() == clazz); assertTrue(lookup.hasPrivateAccess()); // get obj field MethodHandle mh = lookup.findStaticGetter(clazz, "obj", Object.class); Object obj = mh.invokeExact(); }
/** * Basic test of defineClass to define a class in the same package as test. */ @Test public void testDefineClass() throws Exception { final String CLASS_NAME = THIS_PACKAGE + ".Foo"; Lookup lookup = lookup(); Class<?> clazz = lookup.defineClass(generateClass(CLASS_NAME)); // test name assertEquals(clazz.getName(), CLASS_NAME); // test loader/package/protection-domain testSameAbode(clazz, lookup.lookupClass()); // test discoverable testDiscoverable(clazz, lookup); // attempt defineClass again try { lookup.defineClass(generateClass(CLASS_NAME)); assertTrue(false); } catch (LinkageError expected) { } }
/** * MethodHandles.lookup() * * [A0] has module access * [A1] can access all public types in m1 * [A2] can access public types in packages exported by modules that m1 reads * [A3] cannot access public types in non-exported modules of modules that m1 reads */ public void testLookup() throws Exception { Lookup lookup = MethodHandles.lookup(); assertTrue((lookup.lookupModes() & MODULE) == MODULE); // [A0] // m1 findConstructor(lookup, p1_Type1, void.class); // [A1] findConstructor(lookup, p2_Type2, void.class); // [A1] // m2 findConstructor(lookup, q1_Type1, void.class); // [A2] findConstructorExpectingIAE(lookup, q2_Type2, void.class); // [A3] // java.base findConstructor(lookup, Object.class, void.class); // [A2] findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); // [A3] // unnamed findConstructor(lookup, unnamedClass, void.class); // [A3] }
/** * Hop to lookup class in another named module * * [A0] has no access */ public void testFromNamedToNamedModule() throws Exception { Lookup lookup = MethodHandles.lookup().in(q1_Type1); assertTrue(lookup.lookupModes() == 0); // [A0] // m1 findConstructorExpectingIAE(lookup, p1_Type1, void.class); findConstructorExpectingIAE(lookup, p2_Type2, void.class); // m2 findConstructorExpectingIAE(lookup, q1_Type1, void.class); findConstructorExpectingIAE(lookup, q2_Type2, void.class); // java.base findConstructorExpectingIAE(lookup, Object.class, void.class); findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); // unnamed findConstructorExpectingIAE(lookup, unnamedClass, void.class); }
@Override Object invokeDefaultMethod(Method method, Class<?> declaringClass, Object object, Object... args) throws Throwable { // Because the service interface might not be public, we need to use a MethodHandle lookup // that ignores the visibility of the declaringClass. Constructor<Lookup> constructor = Lookup.class.getDeclaredConstructor(Class.class, int.class); constructor.setAccessible(true); return constructor.newInstance(declaringClass, -1 /* trusted */) .unreflectSpecial(method, declaringClass) .bindTo(object) .invokeWithArguments(args); }
public void testRunnableProxy0() throws Throwable { if (CAN_SKIP_WORKING) return; startTest("testRunnableProxy"); MethodHandles.Lookup lookup = MethodHandles.lookup(); MethodHandle run = lookup.findStatic(lookup.lookupClass(), "runForRunnable", MethodType.methodType(void.class)); Runnable r = MethodHandleProxies.asInterfaceInstance(Runnable.class, run); testRunnableProxy(r); assertCalled("runForRunnable"); }
void testFindConstructor(boolean positive, Lookup lookup, Class<?> defc, Class<?>... params) throws Throwable { countTest(positive); MethodType type = MethodType.methodType(void.class, params); MethodHandle target = null; Exception noAccess = null; try { if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" <init>"+type); target = lookup.findConstructor(defc, type); } catch (ReflectiveOperationException ex) { noAccess = ex; assertTrue(noAccess.getClass().getName(), noAccess instanceof IllegalAccessException); } if (verbosity >= 3) System.out.println("findConstructor "+defc.getName()+".<init>/"+type+" => "+target +(target == null ? "" : target.type()) +(noAccess == null ? "" : " !! "+noAccess)); if (positive && noAccess != null) throw noAccess; assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); if (!positive) return; // negative test failed as expected assertEquals(type.changeReturnType(defc), target.type()); Object[] args = randomArgs(params); printCalled(target, defc.getSimpleName(), args); Object obj = target.invokeWithArguments(args); if (!(defc == Example.class && params.length < 2)) assertCalled(defc.getSimpleName()+".<init>", args); assertTrue("instance of "+defc.getName(), defc.isInstance(obj)); }
@Test void lookup() throws Throwable { Mjolnir.get( lookup -> { assertSame(MjolnirTests.class, lookup.lookupClass()); assertTrue((lookup.lookupModes() & Lookup.PRIVATE) != 0); return null; }); }
public MethodHandleData(Object obj) throws IllegalAccessException { this.obj = obj; Lookup lookup = MethodHandles.lookup(); Field[] reflectFields = obj.getClass().getFields(); fields = new MethodHandle[reflectFields.length]; for(int i = 0; i < reflectFields.length; i++) { fields[i] = lookup.unreflectGetter(reflectFields[i]); } }
private static Lookup getCurrentLookup() { final LinkRequest currentRequest = AccessController.doPrivileged(new PrivilegedAction<LinkRequest>() { @Override public LinkRequest run() { return LinkerServicesImpl.getCurrentLinkRequest(); } }); return currentRequest == null ? MethodHandles.publicLookup() : currentRequest.getCallSiteDescriptor().getLookup(); }
/** * Retrieves a Nashorn call site descriptor with the specified values. Since call site descriptors are immutable * this method is at liberty to retrieve canonicalized instances (although it is not guaranteed it will do so). * @param lookup the lookup describing the script * @param name the name at the call site, e.g. {@code "dyn:getProp|getElem|getMethod:color"}. * @param methodType the method type at the call site * @param flags Nashorn-specific call site flags * @return a call site descriptor with the specified values. */ public static NashornCallSiteDescriptor get(final MethodHandles.Lookup lookup, final String name, final MethodType methodType, final int flags) { final String[] tokenizedName = CallSiteDescriptorFactory.tokenizeName(name); assert tokenizedName.length == 2 || tokenizedName.length == 3; assert "dyn".equals(tokenizedName[0]); assert tokenizedName[1] != null; // TODO: see if we can move mangling/unmangling into Dynalink return get(lookup, tokenizedName[1], tokenizedName.length == 3 ? tokenizedName[2].intern() : null, methodType, flags); }
private static NashornCallSiteDescriptor get(final MethodHandles.Lookup lookup, final String operator, final String operand, final MethodType methodType, final int flags) { final NashornCallSiteDescriptor csd = new NashornCallSiteDescriptor(lookup, operator, operand, methodType, flags); // Many of these call site descriptors are identical (e.g. every getter for a property color will be // "dyn:getProp:color(Object)Object", so it makes sense canonicalizing them. final ConcurrentMap<NashornCallSiteDescriptor, NashornCallSiteDescriptor> classCanonicals = canonicals.get(lookup.lookupClass()); final NashornCallSiteDescriptor canonical = classCanonicals.putIfAbsent(csd, csd); return canonical != null ? canonical : csd; }
private NashornCallSiteDescriptor(final MethodHandles.Lookup lookup, final String operator, final String operand, final MethodType methodType, final int flags) { this.lookup = lookup; this.operator = operator; this.operand = operand; this.methodType = methodType; this.flags = flags; }
/** * Returns the lookup secured by this {@code SecureLookupSupplier}. * @return the lookup secured by this {@code SecureLookupSupplier}. * @throws SecurityException if the secured lookup isn't the * {@link MethodHandles#publicLookup()}, and a security manager is present, * and a check for {@code RuntimePermission("dynalink.getLookup")} fails. */ public final Lookup getLookup() { final SecurityManager sm = System.getSecurityManager(); if (sm != null && lookup != MethodHandles.publicLookup()) { sm.checkPermission(GET_LOOKUP_PERMISSION); } return lookup; }
private static boolean lookupsEqual(final Lookup l1, final Lookup l2) { if(l1 == l2) { return true; } if(l1.lookupClass() != l2.lookupClass()) { return false; } return l1.lookupModes() == l2.lookupModes(); }
void testFindStatic(boolean positive, Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { countTest(positive); String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo MethodType type = MethodType.methodType(ret, params); MethodHandle target = null; Exception noAccess = null; try { if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type); target = maybeMoveIn(lookup, defc).findStatic(defc, methodName, type); } catch (ReflectiveOperationException ex) { noAccess = ex; assertExceptionClass( (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("<init>")) ? NoSuchMethodException.class : IllegalAccessException.class, noAccess); if (verbosity >= 5) ex.printStackTrace(System.out); } if (verbosity >= 3) System.out.println("findStatic "+lookup+": "+defc.getName()+"."+name+"/"+type+" => "+target +(noAccess == null ? "" : " !! "+noAccess)); if (positive && noAccess != null) throw noAccess; assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); if (!positive) return; // negative test failed as expected assertEquals(type, target.type()); assertNameStringContains(target, methodName); Object[] args = randomArgs(params); printCalled(target, name, args); target.invokeWithArguments(args); assertCalled(name, args); if (verbosity >= 1) System.out.print(':'); }
void testBind(boolean positive, Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { countTest(positive); String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo MethodType type = MethodType.methodType(ret, params); Object receiver = randomArg(defc); MethodHandle target = null; Exception noAccess = null; try { if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type); target = maybeMoveIn(lookup, defc).bind(receiver, methodName, type); } catch (ReflectiveOperationException ex) { noAccess = ex; assertExceptionClass( (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("<init>")) ? NoSuchMethodException.class : IllegalAccessException.class, noAccess); if (verbosity >= 5) ex.printStackTrace(System.out); } if (verbosity >= 3) System.out.println("bind "+receiver+"."+name+"/"+type+" => "+target +(noAccess == null ? "" : " !! "+noAccess)); if (positive && noAccess != null) throw noAccess; assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); if (!positive) return; // negative test failed as expected assertEquals(type, target.type()); Object[] args = randomArgs(params); printCalled(target, name, args); target.invokeWithArguments(args); Object[] argsWithReceiver = cat(array(Object[].class, receiver), args); assertCalled(name, argsWithReceiver); if (verbosity >= 1) System.out.print(':'); }
public void testSetter(int testMode) throws Throwable { Lookup lookup = PRIVATE; // FIXME: test more lookups than this one startTest("unreflectSetter"); for (Object[] c : HasFields.CASES) { boolean positive = (c[1] != Error.class); testSetter(positive, lookup, c[0], c[1], testMode); if (positive) testSetter(positive, lookup, c[0], c[1], testMode | TEST_NPE); } for (int isStaticN = 0; isStaticN <= 1; isStaticN++) { testSetter(false, lookup, new Object[]{ (isStaticN != 0), System.class, "bogus", char.class }, null, testMode); } }
/** * Test dropLookupMode on the public Lookup. */ public void testPublicLookup() { final Lookup publicLookup = MethodHandles.publicLookup(); final Class<?> lc = publicLookup.lookupClass(); assertTrue(publicLookup.lookupModes() == (PUBLIC|UNCONDITIONAL)); Lookup lookup = publicLookup.dropLookupMode(PRIVATE); assertTrue(lookup.lookupClass() == lc); assertTrue(lookup.lookupModes() == PUBLIC); lookup = publicLookup.dropLookupMode(PROTECTED); assertTrue(lookup.lookupClass() == lc); assertTrue(lookup.lookupModes() == PUBLIC); lookup = publicLookup.dropLookupMode(PACKAGE); assertTrue(lookup.lookupClass() == lc); assertTrue(lookup.lookupModes() == PUBLIC); lookup = publicLookup.dropLookupMode(MODULE); assertTrue(lookup.lookupClass() == lc); assertTrue(lookup.lookupModes() == PUBLIC); lookup = publicLookup.dropLookupMode(PUBLIC); assertTrue(lookup.lookupClass() == lc); assertTrue(lookup.lookupModes() == 0); lookup = publicLookup.dropLookupMode(UNCONDITIONAL); assertTrue(lookup.lookupClass() == lc); assertTrue(lookup.lookupModes() == PUBLIC); }
public void testUserClassInSignature0() throws Throwable { if (CAN_SKIP_WORKING) return; startTest("testUserClassInSignature"); Lookup lookup = MethodHandles.lookup(); String name; MethodType mt; MethodHandle mh; Object[] args; // Try a static method. name = "userMethod"; mt = MethodType.methodType(Example.class, Object.class, String.class, int.class); mh = lookup.findStatic(lookup.lookupClass(), name, mt); assertEquals(mt, mh.type()); assertEquals(Example.class, mh.type().returnType()); args = randomArgs(mh.type().parameterArray()); mh.invokeWithArguments(args); assertCalled(name, args); // Try a virtual method. name = "v2"; mt = MethodType.methodType(Object.class, Object.class, int.class); mh = lookup.findVirtual(Example.class, name, mt); assertEquals(mt, mh.type().dropParameterTypes(0,1)); assertTrue(mh.type().parameterList().contains(Example.class)); args = randomArgs(mh.type().parameterArray()); mh.invokeWithArguments(args); assertCalled(name, args); }
static MethodHandle lookupStatic(Lookup lookup, Class<?> refc, String name, Class<?> rtype, Class<?>... ptypes) { try { return lookup.findStatic(refc, name, MethodType.methodType(rtype, ptypes)); } catch (NoSuchMethodException | IllegalAccessException e) { throw new AssertionError(e); } }
static MethodHandle lookupConstructor(Lookup lookup, Class<?> refc, Class<?> ptypes) { try { return lookup.findConstructor(refc, MethodType.methodType(void.class, ptypes)); } catch (NoSuchMethodException | IllegalAccessException e) { throw new AssertionError(e); } }
public static StackInspector handle(How how) throws Exception { Lookup lookup = MethodHandles.lookup(); MethodHandle mh = lookup.findStatic(Caller.class, "create", MethodType.methodType(StackInspector.class, How.class)); try { return (StackInspector) mh.invoke(how); } catch (Error | Exception x) { throw x; } catch(Throwable t) { throw new AssertionError(t); } }
public static Class<?> handleCaller() throws Exception { Lookup lookup = MethodHandles.lookup(); MethodHandle mh = lookup.findVirtual(StackWalker.class, "getCallerClass", MethodType.methodType(Class.class)); try { return (Class<?>) mh.invoke(walker.get()); } catch (Error | Exception x) { throw x; } catch(Throwable t) { throw new AssertionError(t); } }
public void testAllAccessCallerSameModule() throws Throwable { Lookup lookup = MethodHandles.privateLookupIn(nonPublicType, MethodHandles.lookup()); assertTrue(lookup.lookupClass() == nonPublicType); assertTrue(lookup.hasPrivateAccess()); // get obj field MethodHandle mh = lookup.findStaticGetter(nonPublicType, "obj", Object.class); Object obj = mh.invokeExact(); }
@Test(expectedExceptions = {IllegalAccessException.class}) public void testCallerDoesNotRead() throws Throwable { // m2/p2.Type Class<?> clazz = Class.forName("p2.Type"); assertEquals(clazz.getModule().getName(), "m2"); Module thisModule = getClass().getModule(); Module m2 = clazz.getModule(); assertFalse(thisModule.canRead(m2)); assertTrue(m2.isOpen("p2", thisModule)); Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup()); }
/** * Tests that a class is discoverable by name using Class.forName and * lookup.findClass */ void testDiscoverable(Class<?> clazz, Lookup lookup) throws Exception { String cn = clazz.getName(); ClassLoader loader = clazz.getClassLoader(); assertTrue(Class.forName(cn, false, loader) == clazz); assertTrue(lookup.findClass(cn) == clazz); }
/** * Starting with a full power Lookup, use dropLookupMode to create new Lookups * with reduced access. */ public void testReducingAccess() { Lookup lookup = MethodHandles.lookup(); final Class<?> lc = lookup.lookupClass(); assertTrue(lookup.lookupModes() == (PUBLIC|MODULE|PACKAGE|PROTECTED|PRIVATE)); lookup = lookup.dropLookupMode(PROTECTED); assertTrue(lookup.lookupClass() == lc); assertTrue(lookup.lookupModes() == (PUBLIC|MODULE|PACKAGE|PRIVATE)); lookup = lookup.dropLookupMode(PRIVATE); assertTrue(lookup.lookupClass() == lc); assertTrue(lookup.lookupModes() == (PUBLIC|MODULE|PACKAGE)); lookup = lookup.dropLookupMode(PACKAGE); assertTrue(lookup.lookupClass() == lc); assertTrue(lookup.lookupModes() == (PUBLIC|MODULE)); lookup = lookup.dropLookupMode(MODULE); assertTrue(lookup.lookupClass() == lc); assertTrue(lookup.lookupModes() == PUBLIC); lookup = lookup.dropLookupMode(PUBLIC); assertTrue(lookup.lookupClass() == lc); assertTrue(lookup.lookupModes() == 0); // repeat with lookup has no access lookup = lookup.dropLookupMode(PUBLIC); assertTrue(lookup.lookupClass() == lc); assertTrue(lookup.lookupModes() == 0); }