1.1 --- a/test/compiler/jsr292/methodHandleExceptions/ByteClassLoader.java Fri Nov 22 13:42:46 2013 -0800 1.2 +++ b/test/compiler/jsr292/methodHandleExceptions/ByteClassLoader.java Tue Nov 26 18:16:04 2013 -0500 1.3 @@ -1,3 +1,12 @@ 1.4 +import java.io.BufferedOutputStream; 1.5 +import java.io.FileNotFoundException; 1.6 +import java.io.FileOutputStream; 1.7 +import java.io.IOException; 1.8 +import java.net.URL; 1.9 +import java.net.URLClassLoader; 1.10 +import java.util.jar.JarEntry; 1.11 +import java.util.jar.JarOutputStream; 1.12 + 1.13 /* 1.14 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 1.15 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.16 @@ -23,12 +32,63 @@ 1.17 */ 1.18 1.19 /** 1.20 - * A minimal classloader for loading bytecodes that could not result from 1.21 - * properly compiled Java. 1.22 + * A ByteClassLoader is used to define classes from collections of bytes, as 1.23 + * well as loading classes in the usual way. It includes options to write the 1.24 + * classes to files in a jar, or to read the classes from jars in a later or 1.25 + * debugging run. 1.26 * 1.27 - * @author dr2chase 1.28 + * If Boolean property byteclassloader.verbose is true, be chatty about jar 1.29 + * file operations. 1.30 + * 1.31 */ 1.32 -public class ByteClassLoader extends ClassLoader { 1.33 +public class ByteClassLoader extends URLClassLoader { 1.34 + 1.35 + final static boolean verbose 1.36 + = Boolean.getBoolean("byteclassloader.verbose"); 1.37 + 1.38 + final boolean read; 1.39 + final JarOutputStream jos; 1.40 + final String jar_name; 1.41 + 1.42 + /** 1.43 + * Make a new ByteClassLoader. 1.44 + * 1.45 + * @param jar_name Basename of jar file to be read/written by this classloader. 1.46 + * @param read If true, read classes from jar file instead of from parameter. 1.47 + * @param write If true, write classes to jar files for offline study/use. 1.48 + * 1.49 + * @throws FileNotFoundException 1.50 + * @throws IOException 1.51 + */ 1.52 + public ByteClassLoader(String jar_name, boolean read, boolean write) 1.53 + throws FileNotFoundException, IOException { 1.54 + super(read 1.55 + ? new URL[]{new URL("file:" + jar_name + ".jar")} 1.56 + : new URL[0]); 1.57 + this.read = read; 1.58 + this.jar_name = jar_name; 1.59 + this.jos = write 1.60 + ? new JarOutputStream( 1.61 + new BufferedOutputStream( 1.62 + new FileOutputStream(jar_name + ".jar"))) : null; 1.63 + if (read && write) { 1.64 + throw new Error("At most one of read and write may be true."); 1.65 + } 1.66 + } 1.67 + 1.68 + private static void writeJarredFile(JarOutputStream jos, String file, String suffix, byte[] bytes) { 1.69 + String fileName = file.replace(".", "/") + "." + suffix; 1.70 + JarEntry ze = new JarEntry(fileName); 1.71 + try { 1.72 + ze.setSize(bytes.length); 1.73 + jos.putNextEntry(ze); 1.74 + jos.write(bytes); 1.75 + jos.closeEntry(); 1.76 + } catch (IOException e) { 1.77 + throw new RuntimeException(e); 1.78 + } 1.79 + } 1.80 + 1.81 /** 1.82 * (pre)load class name using classData for the definition. 1.83 * 1.84 @@ -36,9 +96,36 @@ 1.85 * @param classData 1.86 * @return 1.87 */ 1.88 - public Class<?> loadBytes(String name, byte[] classData) { 1.89 - Class<?> clazz = defineClass(name, classData, 0, classData.length); 1.90 - resolveClass(clazz); 1.91 - return clazz; 1.92 + public Class<?> loadBytes(String name, byte[] classData) throws ClassNotFoundException { 1.93 + if (jos != null) { 1.94 + if (verbose) { 1.95 + System.out.println("ByteClassLoader: writing " + name); 1.96 + } 1.97 + writeJarredFile(jos, name, "class", classData); 1.98 + } 1.99 + 1.100 + Class<?> clazz = null; 1.101 + if (read) { 1.102 + if (verbose) { 1.103 + System.out.println("ByteClassLoader: reading " + name + " from " + jar_name); 1.104 + } 1.105 + clazz = loadClass(name); 1.106 + } else { 1.107 + clazz = defineClass(name, classData, 0, classData.length); 1.108 + resolveClass(clazz); 1.109 + } 1.110 + return clazz; 1.111 + } 1.112 + 1.113 + public void close() { 1.114 + if (jos != null) { 1.115 + try { 1.116 + if (verbose) { 1.117 + System.out.println("ByteClassLoader: closing " + jar_name); 1.118 + } 1.119 + jos.close(); 1.120 + } catch (IOException ex) { 1.121 + } 1.122 + } 1.123 } 1.124 }