/* * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ import java.io.DataInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import javax.tools.JavaCompiler; import javax.tools.ToolProvider; /** * A factory that generates a class with many methods. */ public class ClassWithManyMethodsClassLoader extends ClassLoader { /** * Used to enable/disable keeping the class files and java sources for * the generated classes. */ private static boolean deleteFiles = Boolean.parseBoolean( System.getProperty("ClassWithManyMethodsClassLoader.deleteFiles", "true")); private JavaCompiler javac; public ClassWithManyMethodsClassLoader() { javac = ToolProvider.getSystemJavaCompiler(); } private String generateSource(String className, String methodPrefix, int methodCount) { StringBuilder sb = new StringBuilder(); sb.append("public class ") .append(className) .append("{\n"); for (int i = 0; i < methodCount; i++) { sb.append("public void ") .append(methodPrefix) .append(i) .append("() {}\n"); } sb.append("\n}"); return sb.toString(); } private byte[] generateClassBytes(String className, String methodPrefix, int methodCount) throws IOException { String src = generateSource(className, methodPrefix, methodCount); File file = new File(className + ".java"); try (PrintWriter pw = new PrintWriter(new FileWriter(file))) { pw.append(src); pw.flush(); } ByteArrayOutputStream err = new ByteArrayOutputStream(); int exitcode = javac.run(null, null, err, file.getCanonicalPath()); if (exitcode != 0) { // Print Error System.err.print(err); if (err.toString().contains("java.lang.OutOfMemoryError: Java heap space")) { throw new OutOfMemoryError("javac failed with resources exhausted"); } else { throw new RuntimeException("javac failure when compiling: " + file.getCanonicalPath()); } } else { if (deleteFiles) { file.delete(); } } File classFile = new File(className + ".class"); byte[] bytes; try (DataInputStream dis = new DataInputStream(new FileInputStream(classFile))) { bytes = new byte[dis.available()]; dis.readFully(bytes); } if (deleteFiles) { classFile.delete(); } return bytes; } public Class create(String className, String methodPrefix, int methodCount) throws IOException { byte[] bytes = generateClassBytes(className, methodPrefix, methodCount); return defineClass(className, bytes, 0, bytes.length); } }