/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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
* @library ../../../..
* @build test.java.lang.invoke.AccessControlTest
* @build test.java.lang.invoke.AccessControlTest_subpkg.Acquaintance_remote
*/
/**
* Test many combinations of Lookup access and cross-class lookupStatic.
* @author jrose
*/
public class AccessControlTest {
// How much output?
static {
}
final int lookupModes;
}
this.lookupClass = lookupClass;
this.lookupModes = lookupModes;
}
assert(cmp != 0);
return cmp;
}
}
}
}
public int hashCode() {
}
/** Simulate all assertions in the spec. for Lookup.toString. */
if (lookupModes == 0)
suffix = "/noaccess";
else if (lookupModes == PUBLIC)
suffix = "/public";
suffix = "/package";
suffix = "/private";
suffix = "";
else
}
/** Simulate all assertions from the spec. for Lookup.in:
* <hr/>
* Creates a lookup on the specified new lookup class.
* [A1] The resulting object will report the specified
* class as its own {@link #lookupClass lookupClass}.
* <p>
* [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:<ul>
* <li>[A3] If the new lookup class differs from the old one,
* protected members will not be accessible by virtue of inheritance.
* (Protected members may continue to be accessible because of package sharing.)
* <li>[A4] If the new lookup class is in a different package
* than the old one, protected and default (package) members will not be accessible.
* <li>[A5] If the new lookup class is not within the same package member
* as the old one, private members will not be accessible.
* <li>[A6] If the new lookup class is not accessible to the old lookup class,
* using the original access modes,
* then no members, not even public members, will be accessible.
* [A7] (In all other cases, public members will continue to be accessible.)
* </ul>
* Other than the above cases, the new lookup will have the same
* access capabilities as the original. [A8]
* <hr/>
*/
int m1 = lookupModes();
int changed = 0;
assert(samePackage || !sameTopLevel);
assert(sameTopLevel || !sameClass);
if (!accessible) {
// Different package and no access to c2; lose all access.
}
if (!samePackage) {
// Different package; lose PACKAGE and lower access.
}
if (!sameTopLevel) {
// Different top-level class. Lose PRIVATE and lower access.
}
if (!sameClass) {
} else {
}
return l2;
}
return s;
}
/** Predict the success or failure of accessing this method. */
// privacy is strictly enforced on lookups
// protected access is sometimes allowed
}
if (verbosity >= 2)
}
}
c = ec;
assert(c.getEnclosingClass() == null);
return c;
}
while (c.isArray()) c = c.getComponentType();
}
return lc;
}
throw new AssertionError(name);
}
if (i < 0) {
}
return i+1;
}
}
}
// make initial set of lookup test cases
for (Lookup l : originalLookups) {
}
int rounds = 0;
}
}
rounds++;
}
System.out.println("filled in "+CASES.size()+" cases from "+originalLookups.length+" original cases in "+rounds+" rounds");
if (false) {
}
}
}
}
if (verbosity > 0) {
verbosity += 9;
verbosity -= 9;
}
for (int targetAccess : ACCESS_CASES) {
// Try to access target method from various contexts.
}
}
}
System.out.println("tested "+testCount+" access scenarios; "+testCountFails+" accesses were denied");
}
boolean didAccess = false;
try {
switch (kind) {
case "find":
else
break;
case "unreflect":
break;
default:
throw new AssertionError(kind);
}
didAccess = true;
} catch (ReflectiveOperationException ex) {
accessError = ex;
}
if (willAccess != didAccess) {
}
testCount++;
if (!didAccess) testCountFails++;
}
if (verbosity >= 2)
try {
return method;
} catch (NoSuchMethodException ex) {
}
}
// return "self", "sibling", "nestmate", etc.
}
switch (acc) {
case PUBLIC: return "pub_in_";
case PROTECTED: return "pro_in_";
case PACKAGE: return "pkg_in_";
case PRIVATE: return "pri_in_";
}
assert(false);
return "?";
}
private static final int[] ACCESS_CASES = {
};
/** Return one of the ACCESS_CASES. */
switch (mods) {
case 0: return PACKAGE;
}
throw new AssertionError(mods);
}
if (true) {
} else {
try {
Class<?> remc = Class.forName("test.java.lang.invoke.AccessControlTest_subpkg.Acquaintance_remote");
} catch (ReflectiveOperationException ex) {
}
}
}
return MethodHandles.lookup();
}
static public void pub_in_self() { }
static protected void pro_in_self() { }
static private void pri_in_self() { }
static class Inner_nestmate {
return MethodHandles.lookup();
}
static public void pub_in_nestmate() { }
static protected void pro_in_nestmate() { }
static private void pri_in_nestmate() { }
}
}
class AccessControlTest_sibling {
return MethodHandles.lookup();
}
static public void pub_in_sibling() { }
static protected void pro_in_sibling() { }
static private void pri_in_sibling() { }
}
// This guy tests access from outside the package:
/*
package test.java.lang.invoke.AccessControlTest_subpkg;
public class Acquaintance_remote {
public static Lookup[] lookups() { ...
}
...
}
*/