1 /* 2 * Copyright (c) 2016, 2019, 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 package p; 24 25 import java.lang.invoke.MethodHandle; 26 import java.lang.invoke.MethodHandles; 27 import java.lang.invoke.MethodHandles.Lookup; 28 import java.lang.reflect.Modifier; 29 30 import static java.lang.invoke.MethodHandles.Lookup.*; 31 32 import org.testng.annotations.BeforeTest; 33 import org.testng.annotations.Test; 34 import static org.testng.Assert.*; 35 36 /** 37 * Unit tests for MethodHandles.privateLookupIn 38 */ 39 40 @Test 41 public class PrivateLookupInTests { 42 43 /** 44 * A public and non-public types in the test module but in a different 45 * package to the test class. 46 * 47 * package p.internal; 48 * public class PublicType { 49 * } 50 * 51 * package p.internal; 52 * class NonPublicType { 53 * private static final Object obj = ... 54 * } 55 */ 56 private Class<?> publicType; 57 private Class<?> nonPublicType; 58 59 // initialize and sanity check publicType/nonPublicType 60 @BeforeTest 61 public void init() throws Exception { 62 publicType = Class.forName("p.internal.PublicType"); 63 assertTrue(this.getClass().getModule() == publicType.getModule()); 64 assertNotEquals(this.getClass().getPackageName(), publicType.getPackageName()); 65 assertTrue(Modifier.isPublic(publicType.getModifiers())); 66 67 nonPublicType = Class.forName("p.internal.NonPublicType"); 68 assertTrue(this.getClass().getModule() == nonPublicType.getModule()); 69 assertNotEquals(this.getClass().getPackageName(), nonPublicType.getPackageName()); 70 assertFalse(Modifier.isPublic(nonPublicType.getModifiers())); 71 } 72 73 // Invoke MethodHandles.privateLookupIn with a full-power caller 74 public void testAllAccessCallerSameModule() throws Throwable { 75 Lookup lookup = MethodHandles.privateLookupIn(nonPublicType, MethodHandles.lookup()); 76 assertTrue(lookup.lookupClass() == nonPublicType); 77 assertTrue(lookup.hasPrivateAccess()); 78 79 // get obj field 80 MethodHandle mh = lookup.findStaticGetter(nonPublicType, "obj", Object.class); 81 Object obj = mh.invokeExact(); 82 } 83 84 // Invoke MethodHandles.privateLookupIn with a reduced-power caller 85 @Test(expectedExceptions = {IllegalAccessException.class}) 86 public void testReducedAccessCallerSameModule() throws Throwable { 87 Lookup caller = MethodHandles.lookup().dropLookupMode(PACKAGE); 88 assertTrue((caller.lookupModes() & PRIVATE) == 0); 89 assertTrue((caller.lookupModes() & PACKAGE) == 0); 90 assertTrue((caller.lookupModes() & MODULE) != 0); 91 92 Lookup lookup = MethodHandles.privateLookupIn(nonPublicType, caller); 93 } 94 95 // Invoke MethodHandles.privateLookupIn with the public lookup as caller 96 @Test(expectedExceptions = {IllegalAccessException.class}) 97 public void testPublicLookupSameModule() throws Exception { 98 Lookup caller = MethodHandles.publicLookup(); 99 Lookup lookup = MethodHandles.privateLookupIn(publicType, caller); 100 } 101 102 // test reads m1, open module m1 containing p1 103 public void testTargetClassInOpenModule() throws Throwable { 104 // m1/p1.Type 105 Class<?> clazz = Class.forName("p1.Type"); 106 assertEquals(clazz.getModule().getName(), "m1"); 107 108 // ensure that this module reads m1 109 Module thisModule = getClass().getModule(); 110 Module m1 = clazz.getModule(); 111 thisModule.addReads(clazz.getModule()); 112 assertTrue(m1.isOpen("p1", thisModule)); 113 114 Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup()); 115 assertTrue(lookup.lookupClass() == clazz); 116 assertTrue(lookup.hasPrivateAccess()); 117 118 // get obj field 119 MethodHandle mh = lookup.findStaticGetter(clazz, "obj", Object.class); 120 Object obj = mh.invokeExact(); 121 } 122 123 // test target class in unnamed module 124 public void testTargetClassInUnnamedModule() throws Throwable { 125 Class<?> clazz = Class.forName("Unnamed"); 126 assertFalse(clazz.getModule().isNamed()); 127 128 // thisModule does not read the unnamed module 129 Module thisModule = getClass().getModule(); 130 assertFalse(thisModule.canRead(clazz.getModule())); 131 try { 132 MethodHandles.privateLookupIn(clazz, MethodHandles.lookup()); 133 assertTrue(false); 134 } catch (IllegalAccessException expected) { } 135 136 // thisModule reads the unnamed module 137 thisModule.addReads(clazz.getModule()); 138 Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup()); 139 assertTrue(lookup.lookupClass() == clazz); 140 assertTrue(lookup.hasPrivateAccess()); 141 } 142 143 // test does not read m2, m2 opens p2 to test 144 @Test(expectedExceptions = {IllegalAccessException.class}) 145 public void testCallerDoesNotRead() throws Throwable { 146 // m2/p2.Type 147 Class<?> clazz = Class.forName("p2.Type"); 148 assertEquals(clazz.getModule().getName(), "m2"); 149 150 Module thisModule = getClass().getModule(); 151 Module m2 = clazz.getModule(); 152 assertFalse(thisModule.canRead(m2)); 153 assertTrue(m2.isOpen("p2", thisModule)); 154 155 Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup()); 156 } 157 158 // test reads m3, m3 does not open p3 to test 159 @Test(expectedExceptions = {IllegalAccessException.class}) 160 public void testNotOpenToCaller() throws Throwable { 161 // m3/p2.Type 162 Class<?> clazz = Class.forName("p3.Type"); 163 assertEquals(clazz.getModule().getName(), "m3"); 164 165 Module thisModule = getClass().getModule(); 166 Module m3 = clazz.getModule(); 167 thisModule.addReads(clazz.getModule()); 168 assertFalse(m3.isOpen("p3", thisModule)); 169 170 Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup()); 171 } 172 173 // Invoke MethodHandles.privateLookupIn with a primitive class 174 @Test(expectedExceptions = {IllegalArgumentException.class}) 175 public void testPrimitiveClassAsTargetClass() throws Exception { 176 MethodHandles.privateLookupIn(int.class, MethodHandles.lookup()); 177 } 178 179 // Invoke MethodHandles.privateLookupIn with an array class 180 @Test(expectedExceptions = {IllegalArgumentException.class}) 181 public void testArrayClassAsTargetClass() throws Exception { 182 MethodHandles.privateLookupIn(PrivateLookupInTests[].class, MethodHandles.lookup()); 183 } 184 185 // Invoke MethodHandles.privateLookupIn with a primitive array class 186 @Test(expectedExceptions = {IllegalArgumentException.class}) 187 public void testPrimitiveArrayClassAsTargetClass() throws Exception { 188 MethodHandles.privateLookupIn(int[].class, MethodHandles.lookup()); 189 } 190 191 // Invoke MethodHandles.privateLookupIn with null 192 @Test(expectedExceptions = {NullPointerException.class}) 193 public void testNullTargetClass() throws Exception { 194 MethodHandles.privateLookupIn(null, MethodHandles.lookup()); 195 } 196 197 // Invoke MethodHandles.privateLookupIn with null 198 @Test(expectedExceptions = {NullPointerException.class}) 199 public void testNullCaller() throws Exception { 200 MethodHandles.privateLookupIn(getClass(), null); 201 } 202 }