--- a/hotspot/test/compiler/jsr292/methodHandleExceptions/ByteClassLoader.java Fri Nov 22 13:42:46 2013 -0800
+++ b/hotspot/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) {
+ }
+ }
}
}