package com.zqh.classloader;
/**
* Created by zqhxuyuan on 15-2-28.
*/
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.Arrays;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
public class WatchingClassLoader extends ClassLoader implements Runnable {
private WatchService watcher;
private final static String BUILD_DIR = "classes/build/";
private final static String WATCH_CLASS_DIR = "classes";
public WatchingClassLoader(ClassLoader parent) throws IOException {
super(parent);
watcher = FileSystems.getDefault().newWatchService();
Path toWatch = Paths.get(WATCH_CLASS_DIR);
toWatch.register(watcher, StandardWatchEventKinds.ENTRY_CREATE);
System.out.println("Setup Watcher");
}
private Path compileJavaCode(Path filePath) {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(
null, null, null);
Iterable<? extends JavaFileObject> javaFileObjects = fileManager
.getJavaFileObjects(filePath.toFile());
CompilationTask task = compiler.getTask(null, fileManager, null,
Arrays.asList("-d", BUILD_DIR), null, javaFileObjects);
task.call();
String name = filePath.getFileName().toString()
.replace(".java", ".class");
return Paths.get(BUILD_DIR + name);
}
@Override
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException {
System.out.println("Attempting to load class " + name);
try {
Path toLoad = Paths.get(WATCH_CLASS_DIR + File.separator + name);
if (!Files.exists(toLoad, LinkOption.NOFOLLOW_LINKS)) {
return super.loadClass(name, resolve);
}
if (toLoad.getFileName().toString().contains(".java")) {
toLoad = compileJavaCode(toLoad);
name = toLoad.getFileName().toString().replace(".java", ".class");
}
try (final InputStream inputStream = Files.newInputStream(toLoad,
StandardOpenOption.READ)) {
byte[] data = new byte[inputStream.available()];
inputStream.read(data);
Class<?> clazz = defineClass(name.replace(".class", ""), data,
0, data.length);
resolveClass(clazz);
System.out.println("Class has been loaded");
return clazz;
}
} catch (IOException e) {
e.printStackTrace();
}
return super.loadClass(name, resolve);
}
public void run() {
System.out.println("Begin Watching");
while (true) {
WatchKey key;
try {
key = watcher.take();
} catch (InterruptedException x) {
return;
}
for (WatchEvent<?> event : key.pollEvents()) {
if (event.kind() == StandardWatchEventKinds.ENTRY_CREATE) {
Path created = (Path) event.context();
try {
this.loadClass(created.getFileName().toString(), true);
} catch (ClassNotFoundException e) {
System.err.println("Unable to find class");
}
}
}
key.reset();
}
}
public static void main(String[] args) {
try {
WatchingClassLoader loader = new WatchingClassLoader(
ClassLoader.getSystemClassLoader());
new Thread(loader).start();
try (BufferedReader br = new BufferedReader(new InputStreamReader(
System.in))) {
while (true) {
String className = "";
try {
className = br.readLine();
} catch (IOException ioe) {
ioe.printStackTrace();
System.out.println("IO error trying to get ClassName!");
System.exit(1);
}
try {
Class<?> myClass = Class.forName(className, false,
loader);
for (Method m : myClass.getDeclaredMethods()) {
System.out.println(m.getName());
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}