Skip to content

Commit a4ef8d9

Browse files
committed
splitting compilation and running to 2 diffrent flows
1 parent d84c404 commit a4ef8d9

3 files changed

Lines changed: 82 additions & 34 deletions

File tree

src/main/java/org/mdkt/compiler/ExtendedStandardJavaFileManager.java

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
package org.mdkt.compiler;
22

3-
import java.io.FileNotFoundException;
4-
import java.io.IOException;
5-
import java.util.ArrayList;
6-
import java.util.Arrays;
7-
import java.util.List;
83

94
import javax.tools.FileObject;
105
import javax.tools.ForwardingJavaFileManager;
116
import javax.tools.JavaFileManager;
127
import javax.tools.JavaFileObject;
8+
import java.io.IOException;
9+
import java.util.Arrays;
10+
import java.util.Map;
11+
import java.util.stream.Collectors;
1312

1413
/**
1514
* Created by trung on 5/3/15. Edited by turpid-monkey on 9/25/15, completed
@@ -18,20 +17,20 @@
1817
public class ExtendedStandardJavaFileManager extends
1918
ForwardingJavaFileManager<JavaFileManager> {
2019

21-
private List<CompiledCode> compiledCode = new ArrayList<CompiledCode>();
20+
private Map<String, CompiledCode> compiledCode;
2221
private DynamicClassLoader cl;
2322

2423
/**
2524
* Creates a new instance of ForwardingJavaFileManager.
2625
*
27-
* @param fileManager
28-
* delegate to this file manager
26+
* @param fileManager delegate to this file manager
2927
* @param cl
3028
*/
3129
protected ExtendedStandardJavaFileManager(JavaFileManager fileManager,
32-
DynamicClassLoader cl) {
30+
DynamicClassLoader cl, CompiledCode[] compiledCode) {
3331
super(fileManager);
3432
this.cl = cl;
33+
this.compiledCode = Arrays.stream(compiledCode).collect(Collectors.toMap(CompiledCode::getClassName, c -> c));
3534
}
3635

3736
@Override
@@ -40,8 +39,11 @@ public JavaFileObject getJavaFileForOutput(
4039
JavaFileObject.Kind kind, FileObject sibling) throws IOException {
4140

4241
try {
43-
CompiledCode innerClass = new CompiledCode(className);
44-
compiledCode.add(innerClass);
42+
CompiledCode innerClass = compiledCode.get(className);
43+
if (innerClass == null) {
44+
innerClass = new CompiledCode(className);
45+
compiledCode.put(className, innerClass);
46+
}
4547
cl.addCode(innerClass);
4648
return innerClass;
4749
} catch (Exception e) {

src/main/java/org/mdkt/compiler/InMemoryJavaCompiler.java

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
package org.mdkt.compiler;
22

3-
import java.util.*;
4-
53
import javax.tools.*;
4+
import java.util.*;
65

76
/**
87
* Compile Java sources in-memory
@@ -65,38 +64,62 @@ public InMemoryJavaCompiler ignoreWarnings() {
6564
* @throws Exception
6665
*/
6766
public Map<String, Class<?>> compileAll() throws Exception {
67+
Map<String, byte[]> compiled = compileAllToBytes();
68+
return loadCompiledBytes(compiled);
69+
}
70+
71+
public Class<?> loadCompiledBytes(String className, byte[] compiledClasses) throws ClassNotFoundException {
72+
Map<String, byte[]> map = new HashMap<>();
73+
map.put(className, compiledClasses);
74+
return loadCompiledBytes(map).get(className);
75+
}
76+
77+
public Map<String, Class<?>> loadCompiledBytes(Map<String, byte[]> compiledClasses) throws ClassNotFoundException {
78+
ClassLoader classLoader = new ClassLoader() {
79+
@Override
80+
protected Class<?> findClass(String name) {
81+
byte[] b = compiledClasses.get(name);
82+
return defineClass(name, b, 0, b.length);
83+
}
84+
};
85+
Map<String, Class<?>> classes = new HashMap<>();
86+
for (String className : compiledClasses.keySet()) {
87+
classes.put(className, classLoader.loadClass(className));
88+
}
89+
return classes;
90+
}
91+
92+
public Map<String, byte[]> compileAllToBytes() throws Exception {
6893
if (sourceCodes.size() == 0) {
6994
throw new CompilationException("No source code to compile");
7095
}
7196
Collection<SourceCode> compilationUnits = sourceCodes.values();
72-
CompiledCode[] code;
73-
74-
code = new CompiledCode[compilationUnits.size()];
97+
CompiledCode[] code = new CompiledCode[compilationUnits.size()];
7598
Iterator<SourceCode> iter = compilationUnits.iterator();
7699
for (int i = 0; i < code.length; i++) {
77100
code[i] = new CompiledCode(iter.next().getClassName());
78101
}
79102
DiagnosticCollector<JavaFileObject> collector = new DiagnosticCollector<>();
80-
ExtendedStandardJavaFileManager fileManager = new ExtendedStandardJavaFileManager(javac.getStandardFileManager(null, null, null), classLoader);
103+
ExtendedStandardJavaFileManager fileManager = new ExtendedStandardJavaFileManager(javac.getStandardFileManager(null, null, null), classLoader, code);
81104
JavaCompiler.CompilationTask task = javac.getTask(null, fileManager, collector, options, null, compilationUnits);
82105
boolean result = task.call();
83106
if (!result || collector.getDiagnostics().size() > 0) {
84-
StringBuffer exceptionMsg = new StringBuffer();
107+
StringBuilder exceptionMsg = new StringBuilder();
85108
exceptionMsg.append("Unable to compile the source");
86109
boolean hasWarnings = false;
87110
boolean hasErrors = false;
88111
for (Diagnostic<? extends JavaFileObject> d : collector.getDiagnostics()) {
89112
switch (d.getKind()) {
90-
case NOTE:
91-
case MANDATORY_WARNING:
92-
case WARNING:
93-
hasWarnings = true;
94-
break;
95-
case OTHER:
96-
case ERROR:
97-
default:
98-
hasErrors = true;
99-
break;
113+
case NOTE:
114+
case MANDATORY_WARNING:
115+
case WARNING:
116+
hasWarnings = true;
117+
break;
118+
case OTHER:
119+
case ERROR:
120+
default:
121+
hasErrors = true;
122+
break;
100123
}
101124
exceptionMsg.append("\n").append("[kind=").append(d.getKind());
102125
exceptionMsg.append(", ").append("line=").append(d.getLineNumber());
@@ -107,9 +130,9 @@ public Map<String, Class<?>> compileAll() throws Exception {
107130
}
108131
}
109132

110-
Map<String, Class<?>> classes = new HashMap<String, Class<?>>();
111-
for (String className : sourceCodes.keySet()) {
112-
classes.put(className, classLoader.loadClass(className));
133+
Map<String, byte[]> classes = new HashMap<>();
134+
for (CompiledCode aCode : code) {
135+
classes.put(aCode.getClassName(), aCode.getByteCode());
113136
}
114137
return classes;
115138
}
@@ -139,4 +162,6 @@ public InMemoryJavaCompiler addSource(String className, String sourceCode) throw
139162
sourceCodes.put(className, new SourceCode(className, sourceCode));
140163
return this;
141164
}
165+
166+
142167
}

src/test/java/org/mdkt/compiler/InMemoryJavaCompilerTest.java

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
package org.mdkt.compiler;
22

3-
import java.util.List;
4-
import java.util.Map;
5-
63
import org.junit.Assert;
74
import org.junit.Rule;
85
import org.junit.Test;
96
import org.junit.rules.ExpectedException;
107
import org.slf4j.Logger;
118
import org.slf4j.LoggerFactory;
129

10+
import java.util.List;
11+
import java.util.Map;
12+
1313
public class InMemoryJavaCompilerTest {
1414
private static final Logger logger = LoggerFactory.getLogger(InMemoryJavaCompilerTest.class);
1515

@@ -114,4 +114,25 @@ public void compile_WhenWarningsAndErrors() throws Exception {
114114
throw e;
115115
}
116116
}
117+
118+
@Test
119+
public void compile_save_run() throws Exception {
120+
StringBuffer sourceCode = new StringBuffer();
121+
122+
sourceCode.append("package org.mdkt;\n");
123+
sourceCode.append("public class HelloClass {\n");
124+
sourceCode.append(" public java.util.List<String> hello() { return new java.util.ArrayList(); }");
125+
sourceCode.append("}");
126+
127+
128+
InMemoryJavaCompiler compiler = InMemoryJavaCompiler.newInstance().ignoreWarnings().addSource("org.mdkt.HelloClass", sourceCode.toString());
129+
Map<String, byte[]> compiled = compiler.compileAllToBytes();
130+
byte[] helloClassCode = compiled.get("org.mdkt.HelloClass");
131+
//compiled code is in helloClassCode
132+
133+
134+
Class<?> helloClass = InMemoryJavaCompiler.newInstance().loadCompiledBytes("org.mdkt.HelloClass", helloClassCode);
135+
List<?> res = (List<?>) helloClass.getMethod("hello").invoke(helloClass.newInstance());
136+
Assert.assertEquals(0, res.size());
137+
}
117138
}

0 commit comments

Comments
 (0)