Skip to content
This repository was archived by the owner on Feb 16, 2022. It is now read-only.

Commit 2c8a3ca

Browse files
Merge pull request #1 from StaticDefault/master
Added class compiler.
2 parents 578c30d + eaaa4f5 commit 2c8a3ca

11 files changed

Lines changed: 372 additions & 14 deletions

File tree

.classpath

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,6 @@
66
<attribute name="gradle_used_by_scope" value="main,test"/>
77
</attributes>
88
</classpathentry>
9-
<classpathentry kind="src" output="bin/main" path="src/main/resources">
10-
<attributes>
11-
<attribute name="gradle_scope" value="main"/>
12-
<attribute name="gradle_used_by_scope" value="main,test"/>
13-
</attributes>
14-
</classpathentry>
159
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11/"/>
1610
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
1711
<classpathentry kind="output" path="bin/default"/>

src/main/java/com/realtimetech/reflection/classfile/ClassFileReader.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515
import java.util.jar.JarFile;
1616
import java.util.zip.ZipEntry;
1717

18-
import com.realtimetech.reflection.classfile.classfile.ClassFile;
19-
import com.realtimetech.reflection.classfile.classfile.ClassFileStream;
20-
import com.realtimetech.reflection.classfile.classfile.ClassFileStreamSet;
18+
import com.realtimetech.reflection.classfile.file.ClassFile;
19+
import com.realtimetech.reflection.classfile.file.ClassFileStream;
20+
import com.realtimetech.reflection.classfile.file.ClassFileStreamSet;
2121

2222
public class ClassFileReader {
2323
public enum ClassType {

src/main/java/com/realtimetech/reflection/classfile/DependencyFinder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
import org.objectweb.asm.tree.MethodInsnNode;
1515
import org.objectweb.asm.tree.MethodNode;
1616

17-
import com.realtimetech.reflection.classfile.classfile.ClassFile;
17+
import com.realtimetech.reflection.classfile.file.ClassFile;
1818
import com.realtimetech.reflection.classloader.ClassDynamicLoader;
1919

2020
public class DependencyFinder {
Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
package com.realtimetech.reflection.classfile.compiler;
2+
3+
import java.io.File;
4+
import java.io.IOException;
5+
import java.nio.charset.StandardCharsets;
6+
import java.nio.file.Files;
7+
import java.util.ArrayList;
8+
import java.util.Arrays;
9+
import java.util.HashMap;
10+
import java.util.LinkedList;
11+
import java.util.List;
12+
import java.util.UUID;
13+
14+
import javax.tools.Diagnostic;
15+
import javax.tools.DiagnosticCollector;
16+
import javax.tools.JavaCompiler;
17+
import javax.tools.JavaFileObject;
18+
import javax.tools.StandardJavaFileManager;
19+
import javax.tools.ToolProvider;
20+
21+
import com.realtimetech.reflection.classfile.compiler.Message.MessageType;
22+
import com.realtimetech.reflection.classloader.ClassDynamicLoader;
23+
24+
public class ClassCompiler {
25+
private File jdkDirectory;
26+
27+
private HashMap<String, List<Source>> sourcesMap;
28+
29+
private List<File> classpathFiles;
30+
31+
private ClassLoader parentClassLoader;
32+
private ClassDynamicLoader classDynamicLoader;
33+
34+
private ArrayList<Message> compileMessages;
35+
36+
public ClassCompiler(File jdkDirectory) {
37+
this(ClassLoader.getSystemClassLoader(), jdkDirectory);
38+
}
39+
40+
public ClassCompiler(ClassLoader parentClassLoader, File jdkDirectory) {
41+
this.parentClassLoader = parentClassLoader;
42+
43+
this.jdkDirectory = jdkDirectory;
44+
this.sourcesMap = new HashMap<String, List<Source>>();
45+
this.classpathFiles = new LinkedList<File>();
46+
this.compileMessages = new ArrayList<Message>();
47+
}
48+
49+
public ClassCompiler addSource(String packageName, Source source) {
50+
if (!this.sourcesMap.containsKey(packageName)) {
51+
this.sourcesMap.put(packageName, new LinkedList<Source>());
52+
}
53+
54+
this.sourcesMap.get(packageName).add(source);
55+
56+
return this;
57+
}
58+
59+
public Source getSource(String packageName, String fileName) {
60+
if (this.sourcesMap.containsKey(packageName)) {
61+
List<Source> sources = this.sourcesMap.get(packageName);
62+
63+
for (Source source : sources) {
64+
if (source.getFileName().equalsIgnoreCase(fileName)) {
65+
return source;
66+
}
67+
}
68+
}
69+
70+
return null;
71+
}
72+
73+
public ClassCompiler addClasspath(File classpath) {
74+
if (classpath.exists()) {
75+
String classpathName = classpath.getName();
76+
77+
if (classpathName.endsWith(".jar") && classpathName.endsWith(".class") && classpathName.endsWith(".zip")) {
78+
this.classpathFiles.add(classpath);
79+
}
80+
}
81+
82+
return this;
83+
}
84+
85+
public List<File> getClasspathFiles() {
86+
return classpathFiles;
87+
}
88+
89+
public File getJdkDirectory() {
90+
return jdkDirectory;
91+
}
92+
93+
public ClassDynamicLoader getClassDynamicLoader() {
94+
return this.classDynamicLoader;
95+
}
96+
97+
private void searchClassInDirectory(List<File> classFiles, File directory) {
98+
File[] files = directory.listFiles();
99+
100+
if (files != null) {
101+
for (File file : files) {
102+
if (file.isDirectory()) {
103+
searchClassInDirectory(classFiles, file);
104+
} else if (file.getName().endsWith(".class")) {
105+
classFiles.add(file);
106+
}
107+
}
108+
}
109+
}
110+
111+
public boolean compile() throws IOException {
112+
System.setProperty("java.home", this.jdkDirectory.getAbsolutePath());
113+
114+
File workingDirectory;
115+
116+
do {
117+
workingDirectory = new File("build" + File.separator + UUID.randomUUID().toString() + File.separator);
118+
} while (workingDirectory.exists());
119+
120+
List<File> sourceFiles = new LinkedList<File>();
121+
List<File> classFiles = new LinkedList<File>();
122+
123+
for (String packageName : sourcesMap.keySet()) {
124+
List<Source> sources = sourcesMap.get(packageName);
125+
126+
for (Source source : sources) {
127+
File packageFolder = new File(workingDirectory.getAbsolutePath() + File.separator + packageName.replace(".", File.separator) + File.separator);
128+
File sourceFile = new File(packageFolder.getPath() + File.separator + source.getFileName());
129+
packageFolder.mkdirs();
130+
131+
Files.write(sourceFile.toPath(), source.getSourceCode().getBytes(StandardCharsets.UTF_8));
132+
133+
sourceFiles.add(sourceFile);
134+
}
135+
}
136+
137+
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
138+
139+
String classPath = System.getProperty("java.class.path");
140+
141+
for (File classpathFile : classpathFiles) {
142+
classPath += File.pathSeparator + classpathFile.getAbsolutePath();
143+
}
144+
145+
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
146+
Iterable<String> options = Arrays.asList("-classpath", classPath);
147+
StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);
148+
149+
Iterable<? extends JavaFileObject> compilationUnit = fileManager.getJavaFileObjectsFromFiles(sourceFiles);
150+
JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics, options, null, compilationUnit);
151+
152+
boolean result = task.call();
153+
try {
154+
if (result) {
155+
this.searchClassInDirectory(classFiles, workingDirectory);
156+
this.classDynamicLoader = new ClassDynamicLoader(this.parentClassLoader);
157+
158+
for (File classFile : classFiles) {
159+
String path = classFile.getAbsolutePath().replace(workingDirectory.getAbsolutePath(), "");
160+
String className = path.substring(1, path.lastIndexOf(".")).replace(File.separator, ".");
161+
162+
this.classDynamicLoader.addClassFile(className, Files.readAllBytes(classFile.toPath()));
163+
}
164+
165+
return true;
166+
} else {
167+
this.compileMessages.clear();
168+
for (Diagnostic<?> diagnostic : diagnostics.getDiagnostics()) {
169+
MessageType type = null;
170+
171+
switch (diagnostic.getKind()) {
172+
case ERROR:
173+
type = MessageType.ERROR;
174+
break;
175+
case MANDATORY_WARNING:
176+
type = MessageType.WARNING;
177+
break;
178+
case NOTE:
179+
type = MessageType.NOTE;
180+
break;
181+
case OTHER:
182+
type = MessageType.NOTE;
183+
break;
184+
case WARNING:
185+
type = MessageType.WARNING;
186+
break;
187+
}
188+
189+
this.compileMessages.add(new Message(type, diagnostic.getLineNumber(), diagnostic.getMessage(null)));
190+
}
191+
192+
return false;
193+
}
194+
195+
} finally {
196+
for (File sourceFile : sourceFiles) {
197+
sourceFile.delete();
198+
}
199+
}
200+
}
201+
202+
public ArrayList<Message> getCompileMessages() {
203+
return compileMessages;
204+
}
205+
206+
public void printAllCompileMessages() {
207+
for (Message message : compileMessages) {
208+
System.out.println(message.toString());
209+
}
210+
}
211+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.realtimetech.reflection.classfile.compiler;
2+
3+
public class Message {
4+
public static enum MessageType {
5+
ERROR, WARNING, NOTE
6+
}
7+
8+
private MessageType type;
9+
10+
private long line;
11+
12+
private String message;
13+
14+
public Message(MessageType type, long line, String message) {
15+
this.type = type;
16+
this.line = line;
17+
this.message = message;
18+
}
19+
20+
public MessageType getType() {
21+
return type;
22+
}
23+
24+
public long getLine() {
25+
return line;
26+
}
27+
28+
public String getMessage() {
29+
return message;
30+
}
31+
32+
@Override
33+
public String toString() {
34+
return type + " [ line=" + line + "\t message=" + message + " ]";
35+
}
36+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.realtimetech.reflection.classfile.compiler;
2+
3+
public class Source {
4+
private String fileName;
5+
6+
private String sourceCode;
7+
8+
public Source(String fileName, String sourceCode) {
9+
this.fileName = fileName;
10+
this.sourceCode = sourceCode;
11+
}
12+
13+
public String getFileName() {
14+
return fileName;
15+
}
16+
17+
public void setFileName(String fileName) {
18+
this.fileName = fileName;
19+
}
20+
21+
public String getSourceCode() {
22+
return sourceCode;
23+
}
24+
25+
public void setSourceCode(String sourceCode) {
26+
this.sourceCode = sourceCode;
27+
}
28+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package com.realtimetech.reflection.classfile.compiler.jdk;
2+
3+
import java.io.File;
4+
import java.io.IOException;
5+
import java.nio.file.FileVisitOption;
6+
import java.nio.file.FileVisitResult;
7+
import java.nio.file.Files;
8+
import java.nio.file.Path;
9+
import java.nio.file.Paths;
10+
import java.nio.file.SimpleFileVisitor;
11+
import java.nio.file.attribute.BasicFileAttributes;
12+
import java.util.ArrayList;
13+
import java.util.Arrays;
14+
import java.util.HashSet;
15+
16+
public class JDKFinder {
17+
public static File getDirectory(String version) {
18+
String operatingSystem = System.getProperty("os.name").toLowerCase();
19+
20+
String[] folders = null;
21+
String fileName = null;
22+
23+
if (operatingSystem.indexOf("mac") >= 0 || operatingSystem.indexOf("mac") >= 0) {
24+
folders = new String[] { "." + File.separator, File.separator + "Library" + File.separator + "Java" + File.separator + "JavaVirtualMachines", File.separator + "System" + File.separator + "Library" + File.separator + "Frameworks", File.separator + "usr" + File.separator + "libexec" + File.separator + "java_home" };
25+
fileName = "javac";
26+
} else if (operatingSystem.indexOf("win") >= 0) {
27+
folders = new String[] { "." + File.separator, System.getenv("ProgramFiles") + File.separator + "ojdkbuild", System.getenv("ProgramFiles(X86)") + File.separator + "ojdkbuild", System.getenv("ProgramFiles") + File.separator + "Java", System.getenv("ProgramFiles(X86)") + File.separator + "Java" };
28+
fileName = "javac.exe";
29+
} else if (operatingSystem.indexOf("nux") >= 0) {
30+
folders = new String[] { "." + File.separator, File.separator + "usr" + File.separator + "java", File.separator + "usr" + File.separator + "ojdkbuild", File.separator + "usr" + File.separator + "openjdk" };
31+
fileName = "javac";
32+
}
33+
34+
File lastDirectory = null;
35+
36+
for (String folder : folders) {
37+
File file = new File(folder);
38+
39+
File[] searchFilesInDirectory = searchFilesInDirectory(file, fileName);
40+
41+
if (searchFilesInDirectory.length > 0) {
42+
for (File jdkDirecotory : searchFilesInDirectory) {
43+
String absolutePath = jdkDirecotory.getAbsolutePath();
44+
if (absolutePath.contains(version)) {
45+
return jdkDirecotory.getParentFile().getParentFile();
46+
} else {
47+
lastDirectory = jdkDirecotory.getParentFile().getParentFile();
48+
}
49+
}
50+
}
51+
}
52+
53+
return lastDirectory;
54+
}
55+
56+
private static File[] searchFilesInDirectory(File folder, String fileName) {
57+
ArrayList<File> searchedFiles = new ArrayList<File>();
58+
try {
59+
Files.walkFileTree(Paths.get(folder.getPath()), new HashSet<FileVisitOption>(Arrays.asList(FileVisitOption.FOLLOW_LINKS)), Integer.MAX_VALUE, new SimpleFileVisitor<Path>() {
60+
@Override
61+
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
62+
if (file.getFileName().toString().contains(fileName)) {
63+
searchedFiles.add(file.toFile());
64+
}
65+
return FileVisitResult.CONTINUE;
66+
}
67+
68+
@Override
69+
public FileVisitResult visitFileFailed(Path file, IOException e) throws IOException {
70+
return FileVisitResult.SKIP_SUBTREE;
71+
}
72+
73+
@Override
74+
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
75+
return FileVisitResult.CONTINUE;
76+
}
77+
});
78+
} catch (IOException e) {
79+
e.printStackTrace();
80+
}
81+
82+
return searchedFiles.toArray(new File[searchedFiles.size()]);
83+
}
84+
85+
}

0 commit comments

Comments
 (0)