comparison test/testlibrary/com/oracle/java/testlibrary/InMemoryJavaCompiler.java @ 12063:1a8fb39bdbc4

8014659: NPG: performance counters for compressed klass space Reviewed-by: mgerdin, coleenp, hseigel, jmasa, ctornqvi
author ehelin
date Wed, 07 Aug 2013 16:47:32 +0200
parents
children
comparison
equal deleted inserted replaced
12061:e5003079dfa5 12063:1a8fb39bdbc4
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 package com.oracle.java.testlibrary;
25
26 import java.io.ByteArrayOutputStream;
27 import java.io.IOException;
28 import java.io.OutputStream;
29
30 import java.net.URI;
31 import java.util.Arrays;
32
33 import javax.tools.ForwardingJavaFileManager;
34 import javax.tools.ForwardingJavaFileManager;
35 import javax.tools.FileObject;
36 import javax.tools.JavaCompiler;
37 import javax.tools.JavaCompiler.CompilationTask;
38 import javax.tools.JavaFileManager;
39 import javax.tools.JavaFileObject;
40 import javax.tools.JavaFileObject.Kind;
41 import javax.tools.SimpleJavaFileObject;
42 import javax.tools.ToolProvider;
43
44 /**
45 * {@code InMemoryJavaCompiler} can be used for compiling a {@link
46 * CharSequence} to a {@code byte[]}.
47 *
48 * The compiler will not use the file system at all, instead using a {@link
49 * ByteArrayOutputStream} for storing the byte code. For the source code, any
50 * kind of {@link CharSequence} can be used, e.g. {@link String}, {@link
51 * StringBuffer} or {@link StringBuilder}.
52 *
53 * The {@code InMemoryCompiler} can easily be used together with a {@code
54 * ByteClassLoader} to easily compile and load source code in a {@link String}:
55 *
56 * <pre>
57 * {@code
58 * import com.oracle.java.testlibrary.InMemoryJavaCompiler;
59 * import com.oracle.java.testlibrary.ByteClassLoader;
60 *
61 * class Example {
62 * public static void main(String[] args) {
63 * String className = "Foo";
64 * String sourceCode = "public class " + className + " {" +
65 * " public void bar() {" +
66 * " System.out.println("Hello from bar!");" +
67 * " }" +
68 * "}";
69 * byte[] byteCode = InMemoryJavaCompiler.compile(className, sourceCode);
70 * Class fooClass = ByteClassLoader.load(className, byteCode);
71 * }
72 * }
73 * }
74 * </pre>
75 */
76 public class InMemoryJavaCompiler {
77 private static class MemoryJavaFileObject extends SimpleJavaFileObject {
78 private final String className;
79 private final CharSequence sourceCode;
80 private final ByteArrayOutputStream byteCode;
81
82 public MemoryJavaFileObject(String className, CharSequence sourceCode) {
83 super(URI.create("string:///" + className.replace('.','/') + Kind.SOURCE.extension), Kind.SOURCE);
84 this.className = className;
85 this.sourceCode = sourceCode;
86 this.byteCode = new ByteArrayOutputStream();
87 }
88
89 @Override
90 public CharSequence getCharContent(boolean ignoreEncodingErrors) {
91 return sourceCode;
92 }
93
94 @Override
95 public OutputStream openOutputStream() throws IOException {
96 return byteCode;
97 }
98
99 public byte[] getByteCode() {
100 return byteCode.toByteArray();
101 }
102
103 public String getClassName() {
104 return className;
105 }
106 }
107
108 private static class FileManagerWrapper extends ForwardingJavaFileManager {
109 private MemoryJavaFileObject file;
110
111 public FileManagerWrapper(MemoryJavaFileObject file) {
112 super(getCompiler().getStandardFileManager(null, null, null));
113 this.file = file;
114 }
115
116 @Override
117 public JavaFileObject getJavaFileForOutput(Location location, String className,
118 Kind kind, FileObject sibling)
119 throws IOException {
120 if (!file.getClassName().equals(className)) {
121 throw new IOException("Expected class with name " + file.getClassName() +
122 ", but got " + className);
123 }
124 return file;
125 }
126 }
127
128 /**
129 * Compiles the class with the given name and source code.
130 *
131 * @param className The name of the class
132 * @param sourceCode The source code for the class with name {@code className}
133 * @throws RuntimeException if the compilation did not succeed
134 * @return The resulting byte code from the compilation
135 */
136 public static byte[] compile(String className, CharSequence sourceCode) {
137 MemoryJavaFileObject file = new MemoryJavaFileObject(className, sourceCode);
138 CompilationTask task = getCompilationTask(file);
139
140 if(!task.call()) {
141 throw new RuntimeException("Could not compile " + className + " with source code " + sourceCode);
142 }
143
144 return file.getByteCode();
145 }
146
147 private static JavaCompiler getCompiler() {
148 return ToolProvider.getSystemJavaCompiler();
149 }
150
151 private static CompilationTask getCompilationTask(MemoryJavaFileObject file) {
152 return getCompiler().getTask(null, new FileManagerWrapper(file), null, null, null, Arrays.asList(file));
153 }
154 }