1 /* 2 * Copyright (c) 2019, 2020, 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 24 /* 25 * @test 26 * @bug 8227415 8254975 8270056 27 * @run testng/othervm p.ProtectedMethodInOtherPackage 28 * @summary method reference to a protected method inherited from its 29 * superclass in a different runtime package where 30 * lambda proxy class has no access to it. 31 */ 32 33 package p; 34 35 import q.I; 36 import q.J; 37 38 import java.io.IOException; 39 import java.io.UncheckedIOException; 40 import java.lang.invoke.MethodHandle; 41 import java.lang.invoke.MethodHandles; 42 import java.lang.invoke.MethodType; 43 import java.net.URL; 44 import java.net.URLClassLoader; 45 import java.nio.file.Files; 46 import java.nio.file.Path; 47 import java.nio.file.Paths; 48 import java.util.function.Function; 49 50 import org.testng.annotations.Test; 51 import static org.testng.Assert.*; 52 53 public class ProtectedMethodInOtherPackage { 54 @Test remotePackageSameLoader()55 public static void remotePackageSameLoader() { 56 Sub_I sub = new Sub_I(); 57 sub.test(Paths.get("test")); 58 } 59 60 public static class Sub_J extends J { Sub_J(Function<Path,String> function)61 Sub_J(Function<Path,String> function) { 62 super(function); 63 } 64 } 65 66 public static class Sub_I extends I { test(Path path)67 public void test(Path path) { 68 /* 69 * The method reference to an inherited protected method 70 * in another package is desugared with REF_invokeVirtual on 71 * a bridge method to invoke protected q.I::filename method 72 */ 73 Sub_J c = new Sub_J(this::filename); 74 c.check(path); 75 } 76 } 77 78 @Test splitPackage()79 public static void splitPackage() throws Throwable { 80 ClassLoader parent = new Loader("loader-A", null, A.class); 81 ClassLoader loader = new Loader("loader-B", parent, B.class); 82 Class<?> aClass = Class.forName(A.class.getName(), false, loader); 83 Class<?> bClass = Class.forName(B.class.getName(), false, loader); 84 assertTrue(aClass.getClassLoader() == parent); 85 assertTrue(bClass.getClassLoader() == loader); 86 assertEquals(aClass.getPackageName(), bClass.getPackageName()); 87 88 Object b = bClass.getDeclaredConstructor().newInstance(); 89 90 // verify subclass can access a protected member inherited from 91 // its superclass in a split package 92 MethodHandle test = MethodHandles.lookup() 93 .findVirtual(bClass, "test", MethodType.methodType(void.class)); 94 test.invoke(b); 95 96 // verify lambda can access a protected member inherited from 97 // a superclass of the host class where the superclass is in 98 // a split package (not the same runtime package as the host class) 99 MethodHandle get = MethodHandles.lookup() 100 .findVirtual(bClass, "get", MethodType.methodType(Runnable.class)); 101 ((Runnable) get.invoke(b)).run(); 102 } 103 104 @Test protectedStaticMethodInSplitPackage()105 public static void protectedStaticMethodInSplitPackage() throws Throwable { 106 ClassLoader parent = new Loader("loader-A1", null, A1.class); 107 ClassLoader loader = new Loader("loader-B1", parent, B1.class); 108 Class<?> aClass1 = Class.forName(A1.class.getName(), false, loader); 109 Class<?> bClass1 = Class.forName(B1.class.getName(), false, loader); 110 assertTrue(aClass1.getClassLoader() == parent); 111 assertTrue(bClass1.getClassLoader() == loader); 112 assertEquals(aClass1.getPackageName(), bClass1.getPackageName()); 113 114 // verify subclass can access a static protected method inherited from 115 // its superclass in a split package 116 MethodHandle test = MethodHandles.lookup() 117 .findStatic(bClass1, "test", MethodType.methodType(void.class)); 118 test.invoke(); 119 120 // verify lambda can access a static protected method inherited from 121 // a superclass of the host class where the superclass is in 122 // a split package (not the same runtime package as the host class) 123 MethodHandle get = MethodHandles.lookup() 124 .findStatic(bClass1, "get", MethodType.methodType(Runnable.class)); 125 ((Runnable) get.invoke()).run(); 126 } 127 128 static class Loader extends URLClassLoader { 129 static final Path CLASSES_DIR = Paths.get(System.getProperty("test.class.path")); 130 private final Class<?> c; Loader(String name, ClassLoader parent, Class<?> c)131 Loader(String name, ClassLoader parent, Class<?> c) { 132 super(name, new URL[]{}, parent); 133 this.c = c; 134 } 135 136 @Override findClass(String name)137 protected Class<?> findClass(String name) throws ClassNotFoundException { 138 if (name.equals(c.getName())) { 139 try { 140 String path = name.replace('.', '/') + ".class"; 141 byte[] bytes = Files.readAllBytes(CLASSES_DIR.resolve(path)); 142 return defineClass(name, bytes, 0, bytes.length); 143 } catch (IOException e) { 144 throw new UncheckedIOException(e); 145 } 146 } 147 148 return super.findClass(name); 149 } 150 151 } 152 153 public static class A { func()154 protected void func() { } 155 } 156 157 public static class B extends A { get()158 public Runnable get() { 159 return this::func; 160 } test()161 public void test() { 162 func(); 163 } 164 } 165 166 public static class A1 { func()167 protected static void func() { } 168 } 169 170 public static class B1 extends A1 { get()171 public static Runnable get() { 172 return A1::func; 173 } test()174 public static void test() { 175 func(); 176 } 177 } 178 } 179