Skip to content

Commit 351412c

Browse files
committed
first commit
0 parents  commit 351412c

8 files changed

Lines changed: 191 additions & 0 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.idea
2+
InMemoryJavaCompiler.iml

pom.xml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
5+
<groupId>org.mdkt.compiler</groupId>
6+
<artifactId>InMemoryJavaCompiler</artifactId>
7+
<version>1.0-SNAPSHOT</version>
8+
<packaging>jar</packaging>
9+
10+
<name>InMemoryJavaCompiler</name>
11+
12+
<properties>
13+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
14+
</properties>
15+
16+
<dependencies>
17+
<dependency>
18+
<groupId>junit</groupId>
19+
<artifactId>junit</artifactId>
20+
<version>4.12</version>
21+
<scope>test</scope>
22+
</dependency>
23+
</dependencies>
24+
</project>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package org.mdkt.compiler;
2+
3+
import javax.tools.SimpleJavaFileObject;
4+
import java.io.ByteArrayOutputStream;
5+
import java.io.IOException;
6+
import java.io.OutputStream;
7+
import java.net.URI;
8+
9+
/**
10+
* Created by trung on 5/3/15.
11+
*/
12+
public class CompiledCode extends SimpleJavaFileObject {
13+
private ByteArrayOutputStream baos = new ByteArrayOutputStream();
14+
15+
public CompiledCode(String className) throws Exception {
16+
super(new URI(className), Kind.CLASS);
17+
}
18+
19+
@Override
20+
public OutputStream openOutputStream() throws IOException {
21+
return baos;
22+
}
23+
24+
public byte[] getByteCode() {
25+
return baos.toByteArray();
26+
}
27+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package org.mdkt.compiler;
2+
3+
import java.util.HashMap;
4+
import java.util.Map;
5+
6+
/**
7+
* Created by trung on 5/3/15.
8+
*/
9+
public class DynamicClassLoader extends ClassLoader {
10+
11+
private Map<String, CompiledCode> customCompiledCode = new HashMap<>();
12+
13+
public DynamicClassLoader(ClassLoader parent) {
14+
super(parent);
15+
}
16+
17+
public void setCode(CompiledCode cc) {
18+
customCompiledCode.put(cc.getName(), cc);
19+
}
20+
21+
@Override
22+
protected Class<?> findClass(String name) throws ClassNotFoundException {
23+
CompiledCode cc = customCompiledCode.get(name);
24+
if (cc == null) {
25+
return super.findClass(name);
26+
}
27+
byte[] byteCode = cc.getByteCode();
28+
return defineClass(name, byteCode, 0, byteCode.length);
29+
}
30+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package org.mdkt.compiler;
2+
3+
import javax.tools.FileObject;
4+
import javax.tools.ForwardingJavaFileManager;
5+
import javax.tools.JavaFileManager;
6+
import javax.tools.JavaFileObject;
7+
import java.io.IOException;
8+
9+
/**
10+
* Created by trung on 5/3/15.
11+
*/
12+
public class ExtendedStandardJavaFileManager extends ForwardingJavaFileManager<JavaFileManager> {
13+
14+
private CompiledCode compiledCode;
15+
private DynamicClassLoader cl;
16+
17+
/**
18+
* Creates a new instance of ForwardingJavaFileManager.
19+
*
20+
* @param fileManager delegate to this file manager
21+
* @param cl
22+
*/
23+
protected ExtendedStandardJavaFileManager(JavaFileManager fileManager, CompiledCode compiledCode, DynamicClassLoader cl) {
24+
super(fileManager);
25+
this.compiledCode = compiledCode;
26+
this.cl = cl;
27+
this.cl.setCode(compiledCode);
28+
}
29+
30+
@Override
31+
public JavaFileObject getJavaFileForOutput(JavaFileManager.Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException {
32+
return compiledCode;
33+
}
34+
35+
@Override
36+
public ClassLoader getClassLoader(JavaFileManager.Location location) {
37+
return cl;
38+
}
39+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package org.mdkt.compiler;
2+
3+
import javax.tools.JavaCompiler;
4+
import javax.tools.JavaFileObject;
5+
import javax.tools.ToolProvider;
6+
import java.util.Arrays;
7+
8+
/**
9+
* Created by trung on 5/3/15.
10+
*/
11+
public class InMemoryJavaCompiler {
12+
static JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
13+
14+
public static Class<?> compile(String className, String sourceCodeInText) throws Exception {
15+
SourceCode sourceCode = new SourceCode(className, sourceCodeInText);
16+
CompiledCode compiledCode = new CompiledCode(className);
17+
Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(sourceCode);
18+
DynamicClassLoader cl = new DynamicClassLoader(ClassLoader.getSystemClassLoader());
19+
ExtendedStandardJavaFileManager fileManager = new ExtendedStandardJavaFileManager(javac.getStandardFileManager(null, null, null), compiledCode, cl);
20+
JavaCompiler.CompilationTask task = javac.getTask(null, fileManager, null, null, null, compilationUnits);
21+
boolean result = task.call();
22+
return cl.loadClass(className);
23+
}
24+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package org.mdkt.compiler;
2+
3+
import javax.tools.SimpleJavaFileObject;
4+
import java.io.IOException;
5+
import java.net.URI;
6+
7+
/**
8+
* Created by trung on 5/3/15.
9+
*/
10+
public class SourceCode extends SimpleJavaFileObject {
11+
private String contents = null;
12+
13+
public SourceCode(String className, String contents) throws Exception {
14+
super(URI.create("string:///" + className.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
15+
this.contents = contents;
16+
}
17+
18+
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
19+
return contents;
20+
}
21+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package org.mdkt.compiler;
2+
3+
import org.junit.Assert;
4+
import org.junit.Test;
5+
6+
/**
7+
* Created by trung on 5/3/15.
8+
*/
9+
public class InMemoryJavaCompilerTest {
10+
11+
@Test
12+
public void compile_whenTypical() throws Exception {
13+
StringBuffer sourceCode = new StringBuffer();
14+
15+
sourceCode.append("package org.mdkt;\n");
16+
sourceCode.append("public class HelloClass {\n");
17+
sourceCode.append(" public String hello() { return \"hello\"; }");
18+
sourceCode.append("}");
19+
20+
Class<?> helloClass = InMemoryJavaCompiler.compile("org.mdkt.HelloClass", sourceCode.toString());
21+
Assert.assertNotNull(helloClass);
22+
Assert.assertEquals(1, helloClass.getDeclaredMethods().length);
23+
}
24+
}

0 commit comments

Comments
 (0)