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 }