package ca.uwaterloo.ece.qhanam.jrsrepair.compiler;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject.Kind;
import javax.tools.ToolProvider;
import org.apache.commons.lang3.StringUtils;
/**
* From https://weblogs.java.net/blog/malenkov/archive/2008/12/how_to_compile.html
*/
public class MemoryClassLoader extends ClassLoader {
private final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
private final MemoryFileManager manager = new MemoryFileManager(this.compiler);
public MemoryClassLoader(String classname, String filecontent, String[] classpath, Writer output) {
this(Collections.singletonMap(classname, filecontent), classpath, output);
}
public MemoryClassLoader(Map<String, String> map, String[] classpath, Writer output) {
List<Source> list = new ArrayList<Source>();
for (Map.Entry<String, String> entry : map.entrySet()) {
list.add(new Source(entry.getKey(), Kind.SOURCE, entry.getValue()));
}
List<String> optionList = new ArrayList<String>();
optionList.add("-classpath");
optionList.add(StringUtils.join(classpath, ":"));
optionList.add("-nowarn");
this.compiler.getTask(output, this.manager, null, optionList, null, list).call();
}
/**
* Introduced for JRSRepair. Returns all compiled classes.
* @return
*/
public List<Output> getAllClasses(){
List<Output> classFiles = new LinkedList<Output>();
for(String file : this.manager.map.keySet()){
classFiles.add(this.manager.map.get(file));
}
return classFiles;
}
/**
* Introduced for JRSRepair
* @param name
* @return
*/
public byte[] getClassBytes(String name) {
Output mc = this.manager.map.get(name);
if(mc != null) {
byte[] array = mc.toByteArray();
return array;
}
return null;
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
protected Class findClass(String name) throws ClassNotFoundException {
synchronized (this.manager) {
Output mc = this.manager.map.remove(name);
if (mc != null) {
byte[] array = mc.toByteArray();
return defineClass(name, array, 0, array.length);
}
}
return super.findClass(name);
}
}