comparison test/runtime/testlibrary/GeneratedClassLoader.java @ 10344:699d9df07e59

8009576: Test returns ClassNotFoundException Summary: Small classpath fix and move tests into open Reviewed-by: mgerdin, zgu
author ctornqvi
date Thu, 23 May 2013 17:39:32 +0200
parents
children
comparison
equal deleted inserted replaced
10343:6bd680e9ea35 10344:699d9df07e59
1 /*
2 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
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 import java.io.DataInputStream;
25 import java.io.File;
26 import java.io.FileInputStream;
27 import java.io.FileWriter;
28 import java.io.IOException;
29 import java.io.PrintWriter;
30 import javax.tools.JavaCompiler;
31 import javax.tools.ToolProvider;
32
33 /**
34 * A class loader that generates new classes.
35 * The generated classes are made by first emitting java sources with nested
36 * static classes, these are then compiled and the class files are read back.
37 * Some efforts are made to make the class instances unique and of not insignificant
38 * size.
39 */
40 public class GeneratedClassLoader extends ClassLoader {
41 /**
42 * Holds a pair of class bytecodes and class name (for use with defineClass).
43 */
44 private static class GeneratedClass {
45 public byte[] bytes;
46 public String name;
47 public GeneratedClass(byte[] bytes, String name) {
48 this.bytes = bytes; this.name = name;
49 }
50 }
51
52 /**
53 * Used to uniquely name every class generated.
54 */
55 private static int count = 0;
56 /**
57 * Used to enable/disable keeping the class files and java sources for
58 * the generated classes.
59 */
60 private static boolean deleteFiles = Boolean.parseBoolean(
61 System.getProperty("GeneratedClassLoader.deleteFiles", "true"));
62
63 private static String bigstr =
64 "Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
65 + "In facilisis scelerisque vehicula. Donec congue nisi a "
66 + "leo posuere placerat lobortis felis ultrices. Pellentesque "
67 + "habitant morbi tristique senectus et netus et malesuada "
68 + "fames ac turpis egestas. Nam tristique velit at felis "
69 + "iaculis at tempor sem vestibulum. Sed adipiscing lectus "
70 + "non mi molestie sagittis. Morbi eu purus urna. Nam tempor "
71 + "tristique massa eget semper. Mauris cursus, nulla et ornare "
72 + "vehicula, leo dolor scelerisque metus, sit amet rutrum erat "
73 + "sapien quis dui. Nullam eleifend risus et velit accumsan sed "
74 + "suscipit felis pulvinar. Nullam faucibus suscipit gravida. "
75 + "Pellentesque habitant morbi tristique senectus et netus et "
76 + "malesuada fames ac turpis egestas. Nullam ut massa augue, "
77 + "nec viverra mauris.";
78
79 private static int getNextCount() {
80 return count++;
81 }
82
83 ////// end statics
84
85 private JavaCompiler javac;
86 private String nameBase;
87
88 public GeneratedClassLoader() {
89 javac = ToolProvider.getSystemJavaCompiler();
90 nameBase = "TestSimpleClass";
91 }
92
93 private long getBigValue(int which) {
94 // > 65536 is too large to encode in the bytecode
95 // so this will force us to emit a constant pool entry for this int
96 return (long)which + 65537;
97 }
98
99 private String getBigString(int which) {
100 return bigstr + which;
101 }
102
103 private String getClassName(int count) {
104 return nameBase + count;
105 }
106
107 private String generateSource(int count, int sizeFactor, int numClasses) {
108 StringBuilder sb = new StringBuilder();
109 sb.append("public class ").append(getClassName(count)).append("{\n");
110 for (int j = 0; j < numClasses; ++j) {
111 sb.append("public static class ")
112 .append("Class")
113 .append(j)
114 .append("{\n");
115 for (int i = 0; i < sizeFactor; ++i) {
116 int value = i;
117 sb.append("private long field")
118 .append(i).append(" = ")
119 .append(getBigValue(value++))
120 .append(";\n");
121 sb.append("public long method")
122 .append(i)
123 .append("() {\n");
124 sb.append("return ")
125 .append(getBigValue(value++))
126 .append(";");
127 sb.append("}\n");
128 sb.append("private String str").append(i)
129 .append(" = \"")
130 .append(getBigString(i))
131 .append("\";");
132 }
133 sb.append("\n}");
134 }
135 sb.append("\n}");
136 return sb.toString();
137 }
138
139 private GeneratedClass[] getGeneratedClass(int sizeFactor, int numClasses) throws IOException {
140 int uniqueCount = getNextCount();
141 String src = generateSource(uniqueCount, sizeFactor, numClasses);
142 String className = getClassName(uniqueCount);
143 File file = new File(className + ".java");
144 try (PrintWriter pw = new PrintWriter(new FileWriter(file))) {
145 pw.append(src);
146 pw.flush();
147 }
148 int exitcode = javac.run(null, null, null, file.getCanonicalPath());
149 if (exitcode != 0) {
150 throw new RuntimeException("javac failure when compiling: " +
151 file.getCanonicalPath());
152 } else {
153 if (deleteFiles) {
154 file.delete();
155 }
156 }
157 GeneratedClass[] gc = new GeneratedClass[numClasses];
158 for (int i = 0; i < numClasses; ++i) {
159 String name = className + "$" + "Class" + i;
160 File classFile = new File(name + ".class");
161 byte[] bytes;
162 try (DataInputStream dis = new DataInputStream(new FileInputStream(classFile))) {
163 bytes = new byte[dis.available()];
164 dis.readFully(bytes);
165 }
166 if (deleteFiles) {
167 classFile.delete();
168 }
169 gc[i] = new GeneratedClass(bytes, name);
170 }
171 if (deleteFiles) {
172 new File(className + ".class").delete();
173 }
174 return gc;
175 }
176
177 /**
178 * Generate a single class, compile it and load it.
179 * @param sizeFactor Fuzzy measure of how large the class should be.
180 * @return the Class instance.
181 * @throws IOException
182 */
183 public Class<?> generateClass(int sizeFactor) throws IOException {
184 return getGeneratedClasses(sizeFactor, 1)[0];
185 }
186
187 /**
188 * Generate several classes, compile and load them.
189 * @param sizeFactor Fuzzy measure of how large each class should be.
190 * @param numClasses The number of classes to create
191 * @return an array of the Class instances.
192 * @throws IOException
193 */
194 public Class<?>[] getGeneratedClasses(int sizeFactor, int numClasses) throws IOException {
195 GeneratedClass[] gc = getGeneratedClass(sizeFactor, numClasses);
196 Class<?>[] classes = new Class[numClasses];
197 for (int i = 0; i < numClasses; ++i) {
198 classes[i] = defineClass(gc[i].name, gc[i].bytes, 0 , gc[i].bytes.length);
199 }
200 return classes;
201 }
202 }