/* * Copyright (c) 2012, 2019, 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 test access checking by java.lang.invoke.MethodHandles.Lookup * @compile AccessControlTest.java AccessControlTest_subpkg/Acquaintance_remote.java * @run testng/othervm test.java.lang.invoke.AccessControlTest */ package test.java.lang.invoke; import java.lang.invoke.*; import java.lang.reflect.*; import java.lang.reflect.Modifier; import java.util.*; import org.testng.annotations.*; import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodHandles.Lookup.*; import static java.lang.invoke.MethodType.*; import static org.testng.Assert.*; import test.java.lang.invoke.AccessControlTest_subpkg.Acquaintance_remote; /** * Test many combinations of Lookup access and cross-class lookupStatic. * @author jrose */ public class AccessControlTest { static final Class THIS_CLASS = AccessControlTest.class; // How much output? static int verbosity = 0; static { String vstr = System.getProperty(THIS_CLASS.getSimpleName()+".verbosity"); if (vstr == null) vstr = System.getProperty(THIS_CLASS.getName()+".verbosity"); if (vstr != null) verbosity = Integer.parseInt(vstr); } private class LookupCase implements Comparable { final Lookup lookup; final Class lookupClass; final Class prevLookupClass; final int lookupModes; public LookupCase(Lookup lookup) { this.lookup = lookup; this.lookupClass = lookup.lookupClass(); this.prevLookupClass = lookup.previousLookupClass(); this.lookupModes = lookup.lookupModes(); assert(lookupString().equals(lookup.toString())); numberOf(lookupClass().getClassLoader()); // assign CL# } public LookupCase(Class lookupClass, Class prevLookupClass, int lookupModes) { this.lookup = null; this.lookupClass = lookupClass; this.prevLookupClass = prevLookupClass; this.lookupModes = lookupModes; numberOf(lookupClass().getClassLoader()); // assign CL# } public final Class lookupClass() { return lookupClass; } public final Class prevLookupClass() { return prevLookupClass; } public final int lookupModes() { return lookupModes; } public Lookup lookup() { lookup.getClass(); return lookup; } @Override public int compareTo(LookupCase that) { Class c1 = this.lookupClass(); Class c2 = that.lookupClass(); Class p1 = this.prevLookupClass(); Class p2 = that.prevLookupClass(); if (c1 != c2) { int cmp = c1.getName().compareTo(c2.getName()); if (cmp != 0) return cmp; cmp = numberOf(c1.getClassLoader()) - numberOf(c2.getClassLoader()); assert(cmp != 0); return cmp; } else if (p1 != p2){ if (p1 == null) return 1; else if (p2 == null) return -1; int cmp = p1.getName().compareTo(p2.getName()); if (cmp != 0) return cmp; cmp = numberOf(p1.getClassLoader()) - numberOf(p2.getClassLoader()); assert(cmp != 0); return cmp; } return -(this.lookupModes() - that.lookupModes()); } @Override public boolean equals(Object that) { return (that instanceof LookupCase && equals((LookupCase)that)); } public boolean equals(LookupCase that) { return (this.lookupClass() == that.lookupClass() && this.prevLookupClass() == that.prevLookupClass() && this.lookupModes() == that.lookupModes()); } @Override public int hashCode() { return lookupClass().hashCode() + (lookupModes() * 31); } /** Simulate all assertions in the spec. for Lookup.toString. */ private String lookupString() { String name = lookupClass.getName(); if (prevLookupClass != null) name += "/" + prevLookupClass.getName(); String suffix = ""; if (lookupModes == 0) suffix = "/noaccess"; else if (lookupModes == PUBLIC) suffix = "/public"; else if (lookupModes == UNCONDITIONAL) suffix = "/publicLookup"; else if (lookupModes == (PUBLIC|MODULE)) suffix = "/module"; else if (lookupModes == (PUBLIC|PACKAGE) || lookupModes == (PUBLIC|MODULE|PACKAGE)) suffix = "/package"; else if (lookupModes == (PUBLIC|PACKAGE|PRIVATE) || lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE)) suffix = "/private"; else if (lookupModes == (PUBLIC|PACKAGE|PRIVATE|PROTECTED) || lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED)) suffix = ""; else suffix = "/#"+Integer.toHexString(lookupModes); return name+suffix; } /** Simulate all assertions from the spec. for Lookup.in: *
* Creates a lookup on the specified new lookup class. * [A1] The resulting object will report the specified * class as its own {@link #lookupClass lookupClass}. * [A2] However, the resulting {@code Lookup} object is guaranteed * to have no more access capabilities than the original. * In particular, access capabilities can be lost as follows: