1 /* 2 * Copyright (c) 2016, 2017, 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 public void testReducedAccessCallerSameModule() throws Throwable { 86 Lookup caller = MethodHandles.lookup().dropLookupMode(PACKAGE); 87 assertTrue((caller.lookupModes() & PRIVATE) == 0); 88 assertTrue((caller.lookupModes() & PACKAGE) == 0); 89 assertTrue((caller.lookupModes() & MODULE) != 0); 90 91 Lookup lookup = MethodHandles.privateLookupIn(nonPublicType, caller); 92 assertTrue(lookup.lookupClass() == nonPublicType); 93 assertTrue(lookup.hasPrivateAccess()); 94 95 // use it 96 MethodHandle mh = lookup.findStaticGetter(nonPublicType, "obj", Object.class); 97 Object obj = mh.invokeExact(); 98 } 99 100 // Invoke MethodHandles.privateLookupIn with the public lookup as caller 101 @Test(expectedExceptions = {IllegalAccessException.class}) 102 public void testPublicLookupSameModule() throws Exception { 103 Lookup caller = MethodHandles.publicLookup(); 104 Lookup lookup = MethodHandles.privateLookupIn(publicType, caller); 105 } 106 107 // test reads m1, open module m1 containing p1 108 public void testTargetClassInOpenModule() throws Throwable { 109 // m1/p1.Type 110 Class<?> clazz = Class.forName("p1.Type"); 111 assertEquals(clazz.getModule().getName(), "m1"); 112 113 // ensure that this module reads m1 114 Module thisModule = getClass().getModule(); 115 Module m1 = clazz.getModule(); 116 thisModule.addReads(clazz.getModule()); 117 assertTrue(m1.isOpen("p1", thisModule)); 118 119 Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup()); 120 assertTrue(lookup.lookupClass() == clazz); 121 assertTrue(lookup.hasPrivateAccess()); 122 123 // get obj field 124 MethodHandle mh = lookup.findStaticGetter(clazz, "obj", Object.class); 125 Object obj = mh.invokeExact(); 126 } 127 128 // test target class in unnamed module 129 public void testTargetClassInUnnamedModule() throws Throwable { 130 Class<?> clazz = Class.forName("Unnamed"); 131 assertFalse(clazz.getModule().isNamed()); 132 133 // thisModule does not read the unnamed module 134 Module thisModule = getClass().getModule(); 135 assertFalse(thisModule.canRead(clazz.getModule())); 136 try { 137 MethodHandles.privateLookupIn(clazz, MethodHandles.lookup()); 138 assertTrue(false); 139 } catch (IllegalAccessException expected) { } 140 141 // thisModule reads the unnamed module 142 thisModule.addReads(clazz.getModule()); 143 Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup()); 144 assertTrue(lookup.lookupClass() == clazz); 145 assertTrue(lookup.hasPrivateAccess()); 146 } 147 148 // test does not read m2, m2 opens p2 to test 149 @Test(expectedExceptions = {IllegalAccessException.class}) 150 public void testCallerDoesNotRead() throws Throwable { 151 // m2/p2.Type 152 Class<?> clazz = Class.forName("p2.Type"); 153 assertEquals(clazz.getModule().getName(), "m2"); 154 155 Module thisModule = getClass().getModule(); 156 Module m2 = clazz.getModule(); 157 assertFalse(thisModule.canRead(m2)); 158 assertTrue(m2.isOpen("p2", thisModule)); 159 160 Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup()); 161 } 162 163 // test reads m3, m3 does not open p3 to test 164 @Test(expectedExceptions = {IllegalAccessException.class}) 165 public void testNotOpenToCaller() throws Throwable { 166 // m3/p2.Type 167 Class<?> clazz = Class.forName("p3.Type"); 168 assertEquals(clazz.getModule().getName(), "m3"); 169 170 Module thisModule = getClass().getModule(); 171 Module m3 = clazz.getModule(); 172 thisModule.addReads(clazz.getModule()); 173 assertFalse(m3.isOpen("p3", thisModule)); 174 175 Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup()); 176 } 177 178 // Invoke MethodHandles.privateLookupIn with a primitive class 179 @Test(expectedExceptions = {IllegalArgumentException.class}) 180 public void testPrimitiveClassAsTargetClass() throws Exception { 181 MethodHandles.privateLookupIn(int.class, MethodHandles.lookup()); 182 } 183 184 // Invoke MethodHandles.privateLookupIn with an array class 185 @Test(expectedExceptions = {IllegalArgumentException.class}) 186 public void testArrayClassAsTargetClass() throws Exception { 187 MethodHandles.privateLookupIn(PrivateLookupInTests[].class, MethodHandles.lookup()); 188 } 189 190 // Invoke MethodHandles.privateLookupIn with a primitive array class 191 @Test(expectedExceptions = {IllegalArgumentException.class}) 192 public void testPrimitiveArrayClassAsTargetClass() throws Exception { 193 MethodHandles.privateLookupIn(int[].class, MethodHandles.lookup()); 194 } 195 196 // Invoke MethodHandles.privateLookupIn with null 197 @Test(expectedExceptions = {NullPointerException.class}) 198 public void testNullTargetClass() throws Exception { 199 MethodHandles.privateLookupIn(null, MethodHandles.lookup()); 200 } 201 202 // Invoke MethodHandles.privateLookupIn with null 203 @Test(expectedExceptions = {NullPointerException.class}) 204 public void testNullCaller() throws Exception { 205 MethodHandles.privateLookupIn(getClass(), null); 206 } 207 }