diff test/compiler/jsr292/methodHandleExceptions/ByteClassLoader.java @ 13403:9d15b81d5d1b

8016839: JSR292: AME instead of IAE when calling a method Summary: Catch missing-because-illegal case for itable entries and use an exception-throwing method instead of null. Reviewed-by: acorn, jrose, coleenp
author drchase
date Tue, 26 Nov 2013 18:16:04 -0500
parents dc261f466b6d
children
line wrap: on
line diff
--- a/test/compiler/jsr292/methodHandleExceptions/ByteClassLoader.java	Fri Nov 22 13:42:46 2013 -0800
+++ b/test/compiler/jsr292/methodHandleExceptions/ByteClassLoader.java	Tue Nov 26 18:16:04 2013 -0500
@@ -1,3 +1,12 @@
+import java.io.BufferedOutputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
+
 /*
  * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -23,12 +32,63 @@
  */
 
 /**
- * A minimal classloader for loading bytecodes that could not result from
- * properly compiled Java.
+ * A ByteClassLoader is used to define classes from collections of bytes, as
+ * well as loading classes in the usual way. It includes options to write the
+ * classes to files in a jar, or to read the classes from jars in a later or
+ * debugging run.
+ *
+ * If Boolean property byteclassloader.verbose is true, be chatty about jar
+ * file operations.
  *
- * @author dr2chase
  */
-public class ByteClassLoader extends ClassLoader {
+public class ByteClassLoader extends URLClassLoader {
+
+    final static boolean verbose
+            = Boolean.getBoolean("byteclassloader.verbose");
+
+    final boolean read;
+    final JarOutputStream jos;
+    final String jar_name;
+
+    /**
+     * Make a new ByteClassLoader.
+     *
+     * @param jar_name  Basename of jar file to be read/written by this classloader.
+     * @param read      If true, read classes from jar file instead of from parameter.
+     * @param write     If true, write classes to jar files for offline study/use.
+     *
+     * @throws FileNotFoundException
+     * @throws IOException
+     */
+    public ByteClassLoader(String jar_name, boolean read, boolean write)
+            throws FileNotFoundException, IOException {
+        super(read
+                ? new URL[]{new URL("file:" + jar_name + ".jar")}
+                : new URL[0]);
+        this.read = read;
+        this.jar_name = jar_name;
+        this.jos = write
+                ? new JarOutputStream(
+                new BufferedOutputStream(
+                new FileOutputStream(jar_name + ".jar"))) : null;
+        if (read && write) {
+            throw new Error("At most one of read and write may be true.");
+        }
+    }
+
+    private static void writeJarredFile(JarOutputStream jos, String file, String suffix, byte[] bytes) {
+        String fileName = file.replace(".", "/") + "." + suffix;
+        JarEntry ze = new JarEntry(fileName);
+        try {
+            ze.setSize(bytes.length);
+            jos.putNextEntry(ze);
+            jos.write(bytes);
+            jos.closeEntry();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
     /**
      * (pre)load class name using classData for the definition.
      *
@@ -36,9 +96,36 @@
      * @param classData
      * @return
      */
-    public Class<?> loadBytes(String name, byte[] classData) {
-         Class<?> clazz = defineClass(name, classData, 0, classData.length);
-                     resolveClass(clazz);
-         return clazz;
+    public Class<?> loadBytes(String name, byte[] classData) throws ClassNotFoundException {
+        if (jos != null) {
+            if (verbose) {
+                System.out.println("ByteClassLoader: writing " + name);
+            }
+            writeJarredFile(jos, name, "class", classData);
+        }
+
+        Class<?> clazz = null;
+        if (read) {
+            if (verbose) {
+                System.out.println("ByteClassLoader: reading " + name + " from " + jar_name);
+            }
+            clazz = loadClass(name);
+        } else {
+            clazz = defineClass(name, classData, 0, classData.length);
+            resolveClass(clazz);
+        }
+        return clazz;
+    }
+
+    public void close() {
+        if (jos != null) {
+            try {
+                if (verbose) {
+                    System.out.println("ByteClassLoader: closing " + jar_name);
+                }
+                jos.close();
+            } catch (IOException ex) {
+            }
+        }
     }
 }