< prev index next >

test/jdk/java/lang/invoke/defineHiddenClass/BasicTest.java

Print this page




  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  * @library /test/lib
  27  * @build jdk.test.lib.Utils
  28  *        jdk.test.lib.compiler.CompilerUtils
  29  *        BasicTest
  30  * @run testng/othervm BasicTest
  31  * @run testng/othervm -Xcomp BasicTest
  32  */
  33 
  34 import java.io.File;
  35 import java.io.IOException;
  36 import java.lang.invoke.MethodHandles.Lookup;
  37 import java.lang.invoke.MethodHandles.Lookup.ClassOption;
  38 import static java.lang.invoke.MethodHandles.lookup;

  39 
  40 import java.lang.reflect.Array;
  41 import java.lang.reflect.Method;
  42 import java.nio.charset.StandardCharsets;
  43 import java.nio.file.Files;
  44 import java.nio.file.Path;
  45 import java.nio.file.Paths;
  46 import java.util.Arrays;
  47 import java.util.List;
  48 import java.util.stream.Stream;
  49 
  50 import jdk.test.lib.compiler.CompilerUtils;
  51 import jdk.test.lib.Utils;
  52 
  53 import org.testng.annotations.BeforeTest;
  54 import org.testng.annotations.DataProvider;
  55 import org.testng.annotations.Test;
  56 import static org.testng.Assert.*;
  57 
  58 interface HiddenTest {
  59     void test();
  60 }
  61 
  62 public class BasicTest {
  63 
  64     private static final Path SRC_DIR = Paths.get(Utils.TEST_SRC, "src");
  65     private static final Path CLASSES_DIR = Paths.get("classes");
  66     private static final Path CLASSES_10_DIR = Paths.get("classes_10");
  67 


  68     @BeforeTest
  69     static void setup() throws IOException {
  70         compileSources(SRC_DIR, CLASSES_DIR);
  71 


  72         // compile with --release 10 with no NestHost and NestMembers attribute
  73         compileSources(SRC_DIR.resolve("Outer.java"), CLASSES_10_DIR, "--release", "10");
  74         compileSources(SRC_DIR.resolve("EnclosingClass.java"), CLASSES_10_DIR, "--release", "10");
  75     }
  76 
  77     static void compileSources(Path sourceFile, Path dest, String... options) throws IOException {
  78         Stream<String> ops = Stream.of("-cp", Utils.TEST_CLASSES + File.pathSeparator + CLASSES_DIR);
  79         if (options != null && options.length > 0) {
  80             ops = Stream.concat(ops, Arrays.stream(options));
  81         }
  82         if (!CompilerUtils.compile(sourceFile, dest, ops.toArray(String[]::new))) {
  83             throw new RuntimeException("Compilation of the test failed: " + sourceFile);
  84         }
  85     }
  86 
  87     static Class<?> defineHiddenClass(String name) throws Exception {
  88         byte[] bytes = Files.readAllBytes(CLASSES_DIR.resolve(name + ".class"));
  89         Class<?> hc = lookup().defineHiddenClass(bytes, false).lookupClass();
  90         assertHiddenClass(hc);
  91         singletonNest(hc);


 145         m.setAccessible(true);
 146     }
 147 
 148     // Define a hidden class that uses lambda
 149     // This verifies LambdaMetaFactory supports the caller which is a hidden class
 150     @Test
 151     public void testLambda() throws Throwable {
 152         HiddenTest t = (HiddenTest)defineHiddenClass("Lambda").newInstance();
 153         try {
 154             t.test();
 155         } catch (Error e) {
 156             if (!e.getMessage().equals("thrown by " + t.getClass().getName())) {
 157                 throw e;
 158             }
 159         }
 160     }
 161 
 162     // Verify the nest host and nest members of a hidden class and hidden nestmate class
 163     @Test
 164     public void testHiddenNestHost() throws Throwable {
 165         byte[] hc1 = Files.readAllBytes(CLASSES_DIR.resolve("HiddenClass.class"));
 166         Lookup lookup1 = lookup().defineHiddenClass(hc1, false);
 167         Class<?> host = lookup1.lookupClass();
 168 
 169         byte[] hc2 = Files.readAllBytes(CLASSES_DIR.resolve("Lambda.class"));
 170         Lookup lookup2 = lookup1.defineHiddenClass(hc2, false, ClassOption.NESTMATE);
 171         Class<?> member = lookup2.lookupClass();
 172 
 173         // test nest membership and reflection API
 174         assertTrue(host.isNestmateOf(member));
 175         assertTrue(host.getNestHost() == host);
 176         // getNestHost and getNestMembers return the same value when calling
 177         // on a nest member and the nest host
 178         assertTrue(member.getNestHost() == host.getNestHost());
 179         assertTrue(Arrays.equals(member.getNestMembers(), host.getNestMembers()));
 180         // getNestMembers includes the nest host that can be a hidden class but
 181         // only includes static nest members
 182         assertTrue(host.getNestMembers().length == 1);
 183         assertTrue(host.getNestMembers()[0] == host);
 184     }
 185 
 186     @Test
 187     public void hiddenCantReflect() throws Throwable {
 188         HiddenTest t = (HiddenTest)defineHiddenClass("HiddenCantReflect").newInstance();
 189         t.test();
 190 


 208     @DataProvider(name = "hiddenClasses")
 209     private Object[][] hiddenClasses() {
 210         return new Object[][] {
 211                 new Object[] { "HiddenInterface", false },
 212                 new Object[] { "AbstractClass", false },
 213                 // class file with bad NestHost, NestMembers and InnerClasses or EnclosingMethod attribute
 214                 // define them as nestmate to verify Class::getNestHost and getNestMembers
 215                 new Object[] { "Outer", true },
 216                 new Object[] { "Outer$Inner", true },
 217                 new Object[] { "EnclosingClass", true },
 218                 new Object[] { "EnclosingClass$1", true },
 219         };
 220     }
 221 
 222     @Test(dataProvider = "hiddenClasses")
 223     public void defineHiddenClass(String name, boolean nestmate) throws Exception {
 224         byte[] bytes = Files.readAllBytes(CLASSES_DIR.resolve(name + ".class"));
 225         Class<?> hc;
 226         Class<?> host;
 227         if (nestmate) {
 228             hc = lookup().defineHiddenClass(bytes, false, ClassOption.NESTMATE).lookupClass();
 229             host = lookup().lookupClass().getNestHost();
 230         } else {
 231             hc = lookup().defineHiddenClass(bytes, false).lookupClass();
 232             host = hc;
 233         }
 234         assertTrue(hc.getNestHost() == host);
 235         assertTrue(hc.getNestMembers().length == 1);
 236         assertTrue(hc.getNestMembers()[0] == host);
 237     }
 238 
 239     @Test(expectedExceptions = NoClassDefFoundError.class)
 240     public void hiddenSuperClass() throws Exception {
 241         byte[] bytes = Files.readAllBytes(CLASSES_DIR.resolve("HiddenSuper.class"));
 242         Class<?> hc = lookup().defineHiddenClass(bytes, false).lookupClass();
 243     }
 244 
 245     @Test(expectedExceptions = {IllegalArgumentException.class})
 246     public void cantDefineModule() throws Throwable {
 247         Path src = Paths.get("module-info.java");
 248         Path dir = CLASSES_DIR.resolve("m");
 249         Files.write(src, List.of("module m {}"), StandardCharsets.UTF_8);
 250         compileSources(src, dir);
 251 
 252         byte[] bytes = Files.readAllBytes(dir.resolve("module-info.class"));
 253         lookup().defineHiddenClass(bytes, false);
 254     }
 255 
 256     @Test(expectedExceptions = {IllegalArgumentException.class})
 257     public void cantDefineClassInAnotherPackage() throws Throwable {
 258         Path src = Paths.get("ClassInAnotherPackage.java");
 259         Files.write(src, List.of("package p;", "public class ClassInAnotherPackage {}"), StandardCharsets.UTF_8);
 260         compileSources(src, CLASSES_DIR);
 261 
 262         byte[] bytes = Files.readAllBytes(CLASSES_DIR.resolve("p").resolve("ClassInAnotherPackage.class"));
 263         lookup().defineHiddenClass(bytes, false);
 264     }
 265 
 266     @Test(expectedExceptions = {IllegalAccessException.class})
 267     public void lessPrivilegedLookup() throws Throwable {
 268         Lookup lookup = lookup().dropLookupMode(Lookup.PRIVATE);
 269         byte[] bytes = Files.readAllBytes(CLASSES_DIR.resolve("HiddenClass.class"));
 270         lookup.defineHiddenClass(bytes, false);
 271     }
 272 
 273     @DataProvider(name = "nestedTypesOrAnonymousClass")
 274     private Object[][] nestedTypesOrAnonymousClass() {
 275         return new Object[][] {
 276                 // class file with bad InnerClasses or EnclosingMethod attribute
 277                 new Object[] { "Outer", null },
 278                 new Object[] { "Outer$Inner", "Outer" },
 279                 new Object[] { "EnclosingClass", null },
 280                 new Object[] { "EnclosingClass$1", "EnclosingClass" },
 281         };
 282     }
 283 
 284     @Test(dataProvider = "nestedTypesOrAnonymousClass")
 285     public void hasInnerClassesOrEnclosingMethodAttribute(String className, String badDeclaringClassName) throws Throwable {
 286         byte[] bytes = Files.readAllBytes(CLASSES_10_DIR.resolve(className + ".class"));
 287         Class<?> hc = lookup().defineHiddenClass(bytes, false).lookupClass();
 288         hiddenClassWithBadAttribute(hc, badDeclaringClassName);
 289     }
 290 




  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  * @library /test/lib
  27  * @build jdk.test.lib.Utils
  28  *        jdk.test.lib.compiler.CompilerUtils
  29  *        BasicTest
  30  * @run testng/othervm BasicTest
  31  * @run testng/othervm -Xcomp BasicTest
  32  */
  33 
  34 import java.io.File;
  35 import java.io.IOException;
  36 import java.lang.invoke.MethodHandles.Lookup;
  37 
  38 import static java.lang.invoke.MethodHandles.lookup;
  39 import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*;
  40 
  41 import java.lang.reflect.Array;
  42 import java.lang.reflect.Method;
  43 import java.nio.charset.StandardCharsets;
  44 import java.nio.file.Files;
  45 import java.nio.file.Path;
  46 import java.nio.file.Paths;
  47 import java.util.Arrays;
  48 import java.util.List;
  49 import java.util.stream.Stream;
  50 
  51 import jdk.test.lib.compiler.CompilerUtils;
  52 import jdk.test.lib.Utils;
  53 
  54 import org.testng.annotations.BeforeTest;
  55 import org.testng.annotations.DataProvider;
  56 import org.testng.annotations.Test;
  57 import static org.testng.Assert.*;
  58 
  59 interface HiddenTest {
  60     void test();
  61 }
  62 
  63 public class BasicTest {
  64 
  65     private static final Path SRC_DIR = Paths.get(Utils.TEST_SRC, "src");
  66     private static final Path CLASSES_DIR = Paths.get("classes");
  67     private static final Path CLASSES_10_DIR = Paths.get("classes_10");
  68 
  69     private static byte[] hiddenClassBytes;
  70 
  71     @BeforeTest
  72     static void setup() throws IOException {
  73         compileSources(SRC_DIR, CLASSES_DIR);
  74 
  75         hiddenClassBytes = Files.readAllBytes(CLASSES_DIR.resolve("HiddenClass.class"));
  76 
  77         // compile with --release 10 with no NestHost and NestMembers attribute
  78         compileSources(SRC_DIR.resolve("Outer.java"), CLASSES_10_DIR, "--release", "10");
  79         compileSources(SRC_DIR.resolve("EnclosingClass.java"), CLASSES_10_DIR, "--release", "10");
  80     }
  81 
  82     static void compileSources(Path sourceFile, Path dest, String... options) throws IOException {
  83         Stream<String> ops = Stream.of("-cp", Utils.TEST_CLASSES + File.pathSeparator + CLASSES_DIR);
  84         if (options != null && options.length > 0) {
  85             ops = Stream.concat(ops, Arrays.stream(options));
  86         }
  87         if (!CompilerUtils.compile(sourceFile, dest, ops.toArray(String[]::new))) {
  88             throw new RuntimeException("Compilation of the test failed: " + sourceFile);
  89         }
  90     }
  91 
  92     static Class<?> defineHiddenClass(String name) throws Exception {
  93         byte[] bytes = Files.readAllBytes(CLASSES_DIR.resolve(name + ".class"));
  94         Class<?> hc = lookup().defineHiddenClass(bytes, false).lookupClass();
  95         assertHiddenClass(hc);
  96         singletonNest(hc);


 150         m.setAccessible(true);
 151     }
 152 
 153     // Define a hidden class that uses lambda
 154     // This verifies LambdaMetaFactory supports the caller which is a hidden class
 155     @Test
 156     public void testLambda() throws Throwable {
 157         HiddenTest t = (HiddenTest)defineHiddenClass("Lambda").newInstance();
 158         try {
 159             t.test();
 160         } catch (Error e) {
 161             if (!e.getMessage().equals("thrown by " + t.getClass().getName())) {
 162                 throw e;
 163             }
 164         }
 165     }
 166 
 167     // Verify the nest host and nest members of a hidden class and hidden nestmate class
 168     @Test
 169     public void testHiddenNestHost() throws Throwable {
 170         byte[] hc1 = hiddenClassBytes;
 171         Lookup lookup1 = lookup().defineHiddenClass(hc1, false);
 172         Class<?> host = lookup1.lookupClass();
 173 
 174         byte[] hc2 = Files.readAllBytes(CLASSES_DIR.resolve("Lambda.class"));
 175         Lookup lookup2 = lookup1.defineHiddenClass(hc2, false, NESTMATE);
 176         Class<?> member = lookup2.lookupClass();
 177 
 178         // test nest membership and reflection API
 179         assertTrue(host.isNestmateOf(member));
 180         assertTrue(host.getNestHost() == host);
 181         // getNestHost and getNestMembers return the same value when calling
 182         // on a nest member and the nest host
 183         assertTrue(member.getNestHost() == host.getNestHost());
 184         assertTrue(Arrays.equals(member.getNestMembers(), host.getNestMembers()));
 185         // getNestMembers includes the nest host that can be a hidden class but
 186         // only includes static nest members
 187         assertTrue(host.getNestMembers().length == 1);
 188         assertTrue(host.getNestMembers()[0] == host);
 189     }
 190 
 191     @Test
 192     public void hiddenCantReflect() throws Throwable {
 193         HiddenTest t = (HiddenTest)defineHiddenClass("HiddenCantReflect").newInstance();
 194         t.test();
 195 


 213     @DataProvider(name = "hiddenClasses")
 214     private Object[][] hiddenClasses() {
 215         return new Object[][] {
 216                 new Object[] { "HiddenInterface", false },
 217                 new Object[] { "AbstractClass", false },
 218                 // class file with bad NestHost, NestMembers and InnerClasses or EnclosingMethod attribute
 219                 // define them as nestmate to verify Class::getNestHost and getNestMembers
 220                 new Object[] { "Outer", true },
 221                 new Object[] { "Outer$Inner", true },
 222                 new Object[] { "EnclosingClass", true },
 223                 new Object[] { "EnclosingClass$1", true },
 224         };
 225     }
 226 
 227     @Test(dataProvider = "hiddenClasses")
 228     public void defineHiddenClass(String name, boolean nestmate) throws Exception {
 229         byte[] bytes = Files.readAllBytes(CLASSES_DIR.resolve(name + ".class"));
 230         Class<?> hc;
 231         Class<?> host;
 232         if (nestmate) {
 233             hc = lookup().defineHiddenClass(bytes, false, NESTMATE).lookupClass();
 234             host = lookup().lookupClass().getNestHost();
 235         } else {
 236             hc = lookup().defineHiddenClass(bytes, false).lookupClass();
 237             host = hc;
 238         }
 239         assertTrue(hc.getNestHost() == host);
 240         assertTrue(hc.getNestMembers().length == 1);
 241         assertTrue(hc.getNestMembers()[0] == host);
 242     }
 243 
 244     @Test(expectedExceptions = NoClassDefFoundError.class)
 245     public void hiddenSuperClass() throws Exception {
 246         byte[] bytes = Files.readAllBytes(CLASSES_DIR.resolve("HiddenSuper.class"));
 247         Class<?> hc = lookup().defineHiddenClass(bytes, false).lookupClass();
 248     }
 249 
 250     @Test(expectedExceptions = {IllegalArgumentException.class})
 251     public void cantDefineModule() throws Throwable {
 252         Path src = Paths.get("module-info.java");
 253         Path dir = CLASSES_DIR.resolve("m");
 254         Files.write(src, List.of("module m {}"), StandardCharsets.UTF_8);
 255         compileSources(src, dir);
 256 
 257         byte[] bytes = Files.readAllBytes(dir.resolve("module-info.class"));
 258         lookup().defineHiddenClass(bytes, false);
 259     }
 260 
 261     @Test(expectedExceptions = {IllegalArgumentException.class})
 262     public void cantDefineClassInAnotherPackage() throws Throwable {
 263         Path src = Paths.get("ClassInAnotherPackage.java");
 264         Files.write(src, List.of("package p;", "public class ClassInAnotherPackage {}"), StandardCharsets.UTF_8);
 265         compileSources(src, CLASSES_DIR);
 266 
 267         byte[] bytes = Files.readAllBytes(CLASSES_DIR.resolve("p").resolve("ClassInAnotherPackage.class"));
 268         lookup().defineHiddenClass(bytes, false);
 269     }
 270 
 271     @Test(expectedExceptions = {IllegalAccessException.class})
 272     public void lessPrivilegedLookup() throws Throwable {
 273         Lookup lookup = lookup().dropLookupMode(Lookup.PRIVATE);
 274         lookup.defineHiddenClass(hiddenClassBytes, false);

 275     }
 276 
 277     @DataProvider(name = "nestedTypesOrAnonymousClass")
 278     private Object[][] nestedTypesOrAnonymousClass() {
 279         return new Object[][] {
 280                 // class file with bad InnerClasses or EnclosingMethod attribute
 281                 new Object[] { "Outer", null },
 282                 new Object[] { "Outer$Inner", "Outer" },
 283                 new Object[] { "EnclosingClass", null },
 284                 new Object[] { "EnclosingClass$1", "EnclosingClass" },
 285         };
 286     }
 287 
 288     @Test(dataProvider = "nestedTypesOrAnonymousClass")
 289     public void hasInnerClassesOrEnclosingMethodAttribute(String className, String badDeclaringClassName) throws Throwable {
 290         byte[] bytes = Files.readAllBytes(CLASSES_10_DIR.resolve(className + ".class"));
 291         Class<?> hc = lookup().defineHiddenClass(bytes, false).lookupClass();
 292         hiddenClassWithBadAttribute(hc, badDeclaringClassName);
 293     }
 294 


< prev index next >