I made a java project, the project only contais this class:
package test.processor;
public abstract class Processor {
public abstract void loadData(String objectId);
public abstract void processData();
public abstract void saveData(String objectId);
}
The project is exported as a jar file (processor.jar)
Then I made another project that imports processor.jar and there is a class that extends Processor:
package test.process;
import test.processor.Processor;
public class Process extends Processor{
#Override
public void loadData(String objectId) {
System.out.println("LOAD DATAAAAAAAAAAAA");
}
#Override
public void processData() {
System.out.println("PROCESS DATAAAAAAAAAAAA");
}
#Override
public void saveData(String objectId) {
System.out.println("SAVE DATAAAAAAAAAAAA");
}
}
This project is also exported as jar (plugin.jar).
Finally, I coded something to load the plugins dynamically:
import test.processor.Processor;
public class Test {
public void testPlugins(){
Processor plugin = (Processor) loadJar(
"C:\\Users\\...\\Desktop\\plugin.jar",
"test.process.Process");
processor.loadData("dada");
}
private Object loadJar(String jar, String className){
File jarFile = new File(jar);
Object instance = null;
try {
URL jarpath = jarFile.toURI().toURL();
String jarUrl = "jar:" + jarpath + "!/";
URL urls[] = { new URL(jarUrl) };
URLClassLoader child = new URLClassLoader(urls);
Class classToLoad = Class.forName(nomeClasse, true, child);
instance = classToLoad.newInstance();
} catch (Exception ex) {
ex.printStackTrace();
}
return instance;
}
}
If I run that code inside a main method it works correctly, once I try to run it in the server there is a problem when loading the class, I get a ClassNotFoundException (Processor).
I tried putting the jar in the tomcat/lib, project/WEB-INF/lib and nothing changed.
Any idea of what Im doing wrong?
I didn't solve it the way I wanted, but I solved it:
First I tried loading the process.jar manually:
private Object loadJars(String processJar, String pluginJar, String className){
File processJarFile = new File(processJar);
File pluginJarFile = new File(pluginJar);
Object instance = null;
try {
URL processJarPath = processJarFile.toURI().toURL();
String processJarUrl = "jar:" + processJarPath + "!/";
URL pluginJarPath = pluginJarFile.toURI().toURL();
String pluginJarUrl = "jar:" + pluginJarPath + "!/";
URL urls[] = { new URL(processJarUrl), new URL(pluginJarUrl) };
URLClassLoader child = new URLClassLoader(urls);
Class classToLoad = Class.forName(nomeClasse, true, child);
instance = classToLoad.newInstance();
} catch (Exception ex) {
ex.printStackTrace();
}
return instance;
}
That loads the Process class correctly, the problem happens in the testPlugins mehod, once it tries to cast to Processor (ClassCastException, can't cast Process to Processor):
public void testPlugins(){
Processor plugin = (Processor) loadJars("C:\\Users\\...\\Desktop\\processor.jar",
"C:\\Users\\...\\Desktop\\plugin.jar",
"test.process.Process");
processor.loadData("dada");
}
Still need to read a lot about classloading but I guess the problem is that it doesn't recognize the Processor loaded from C:\Users\...\Desktop\processor.jar as the same as the Processor loaded from the webapp context or it "forgets" Process extends Processor.
I was in a hurry so I didn't have time to research, to solve the problem I invoked the methods using reflection:
public void modifiedTestPlugins(){
Object plugin = loadJar("C:\\Users\\...\\Desktop\\processor.jar",
"C:\\Users\\...\\Desktop\\plugin.jar",
"test.process.Process");
try {
Method processData = findMethod(obj.getClass(), "processData");
//here I invoke the processData method, it prints: PROCESS DATAAAAAAAAAAAA
loadData.invoke(processData, new Object[]{});
} catch (Exception e) {
e.printStackTrace();
}
}
private static Method findMethod(Class clazz, String methodName) throws Exception {
Method[] methods = clazz.getMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName))
return methods[i];
}
return null;
}
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
Objective:
Run a class
Change a second class
Save and Compile second class
Without stopping and starting first class the changes to second class should be visible in the console
Problem:
Currently the changes do not reflect after saving and compiling.
I think Joachim's code fragment works perfectly fine (not tested):
public class Autosaver implements Runnable {
public static void main(String args[]) {
Autosaver instance = new Autosaver();
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(instance, 0, 5, TimeUnit.SECONDS);
}
#Override
public void run() {
try {
Class<? extends Test> Test_class = reloadClass(Test.class.getProtectionDomain().getCodeSource().getLocation(), Test.class.getName());
new Autorunner(Test_class, new File("Test.txt")).run();
} catch (Exception e) {
e.printStackTrace();
}
}
private static <X> Class<X> reloadClass(URL classLocation, String className) throws ClassNotFoundException, IOException {
URLClassLoader loader = new URLClassLoader(new URL[] { classLocation }, String.class.getClassLoader());
#SuppressWarnings({"unchecked"})
Class<X> result = (Class<X>) loader.loadClass(className);
loader.close();
return result;
}
}
If you want to reload a changed classfile, you don't have to ask the classloader which has already loaded the pre-version, this will deliver always this already loaded version . Use a new classloader, for example
...
Class<?> reloadClass(String classLocation, String className) throws Exception {
URL url = new File(classLocation).toURI().toURL();
URLClassLoader cl = new URLClassLoader(new URL[] { url }, String.class.getClassLoader());
Class<?> c = cl.loadClass(className);
cl.close();
return c;
}
...
EDIT:
Ok, i tested it with a simplified version of your code. The changes in my is only a little bit cosmetic (copied from Binkan Salaryman). It works.
public class Autorunner extends Thread {
private Class runnable;
private File output;
public Autorunner(Class runnable, File output) {
this.runnable = runnable;
this.output = output;
}
#Override
public void run() {
try {
//This is only to get the location of the classfile
URL url = Test.class.getProtectionDomain().getCodeSource().getLocation();
Class runtimeClass = reloadClass(url,Test.class.getName());
Method method = runtimeClass.getMethod("main", String[].class);
method.invoke(null, (Object) null);
System.out.flush();
} catch (NoSuchMethodException | SecurityException | IOException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | ClassNotFoundException ex) {
}
}
Class<?> reloadClass(URL classLocation, String className) throws ClassNotFoundException, IOException {
URLClassLoader cl = new URLClassLoader(new URL[] { classLocation }, String.class.getClassLoader());
Class<?> c = cl.loadClass(className);
cl.close();
return c;
}
Here is a tested, fully working, demonstrative class hotswap test program.
Before running, you need to create "./Test.jar" and "./tmp/Test.jar" and put in a file "Test.class" (without package in code, without folder in jar) you've compiled with a main method and a System.out.println statement.
If something does not work as expected, be sure to give detailed error descriptions and what you've tried.
Code for "./Autosaver.jar" (name doesn't matter):
public class Program {
private static final File Test_classLocation = new File("./Test.jar");
private static final File alternativeTest_classLocation = new File("./tmp/Test.jar");
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
System.out.println("Test.class location = " + Test_classLocation.getAbsolutePath());
System.out.println("alternative Test.class location = " + alternativeTest_classLocation.getAbsolutePath());
while (true) {
testInvocation();
swapFiles(Test_classLocation, alternativeTest_classLocation);
Thread.sleep(3000L);
testInvocation();
swapFiles(Test_classLocation, alternativeTest_classLocation);
Thread.sleep(3000L);
}
}
private static void testInvocation() throws IOException, ClassNotFoundException {
Class<?> Test_class = reloadClass(Test_classLocation.toURI().toURL(), "Test");
invokeMain(Test_class, new String[0]);
}
private static void swapFiles(File a, File b) throws IOException {
Path aTempPath = new File(b.getAbsolutePath() + ".tmp").toPath();
Files.move(a.toPath(), aTempPath);
Files.move(b.toPath(), a.toPath());
Files.move(aTempPath, b.toPath());
}
private static <X> Class<X> reloadClass(URL classLocation, String className) throws ClassNotFoundException, IOException {
URLClassLoader loader = new URLClassLoader(new URL[]{classLocation}, null);
#SuppressWarnings({"unchecked"})
Class<X> result = (Class<X>) loader.loadClass(className);
loader.close();
return result;
}
private static void invokeMain(Class<?> mainClass, String[] args) {
try {
Method mainMethod = mainClass.getDeclaredMethod("main", String[].class);
mainMethod.invoke(null, new Object[]{args});
} catch (NoSuchMethodException | IllegalAccessException e) {
throw new Error(e);
} catch (InvocationTargetException e) {
System.err.println("invocation of " + mainClass.getName() + ".main(" + String.join(",", args) + ") threw an exception:");
e.printStackTrace();
}
}
}
Code for "./Test.jar!Test.class":
public class Test {
public static void main(String[] args) {
System.out.println("old " + Test.class);
}
}
Code for "./tmp/Test.jar!Test.class":
public class Test {
public static void main(String[] args) {
System.out.println("new" + Test.class);
}
}
Output:
Test.class location = D:\rd\test\out\artifacts\Autosaver\.\Test.jar
alternative Test.class location = D:\rd\test\out\artifacts\Autosaver\.\tmp\Test.jar
new class Test
old class Test
new class Test
old class Test
new class Test
old class Test
new class Test
old class Test
new class Test
old class Test
new class Test
old class Test
new class Test
old class Test
new class Test
old class Test
new class Test
...
You can download a zip of the demo here.
When trying to implement a sandbox in a plugin-like environment, I came accross https://stackoverflow.com/a/5580239/2057294 which seems to be exactly what I want, however I am unable to get it working, what am I doing wrong?
I have the following setup:
final class ModURLClassLoader extends URLClassLoader {
ModURLClassLoader(final URL[] urls) {
super(urls);
}
ModURLClassLoader(final URL[] urls, final ClassLoader parent) {
super(urls, parent);
}
ModURLClassLoader(final URL[] urls, final ClassLoader parent, final URLStreamHandlerFactory factory) {
super(urls, parent, factory);
}
#Override
protected PermissionCollection getPermissions(final CodeSource codesource) {
PermissionCollection permissionCollection = super.getPermissions(codesource);
//give no permissions to the codesource
return permissionCollection;
}
#Override
protected Class<?> loadClass(final String name, final boolean resolve) throws ClassNotFoundException {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
int i = name.lastIndexOf('.');
if (i != -1) {
sm.checkPackageAccess(name.substring(0, i));
}
}
return super.loadClass(name, resolve);
}
}
The idea here is that code loaded through the ModURLClassLoader may have no permissions at all. I do want to be able to add extra permissions statically in case I block some permissions which a mod would generally want to have.
Then I load up my classes via the following:
public class JavaMod extends LoadableMod {
private ECSMod ecsMod;
private ModURLClassLoader modUrlClassLoader;
JavaMod(final Path modDirectory) throws ModNotLoadableException {
super(modDirectory);
}
#Override
protected void load0() throws ModNotLoadableException {
try {
Properties properties = ModLoaderHelper.getConfiguration(modDirectory);
String jarName = properties.getProperty("jar");
String entryPoint = properties.getProperty("entryPoint");
Path jarPath = modDirectory.resolve(jarName);
try {
modUrlClassLoader = AccessController.doPrivileged((PrivilegedExceptionAction<ModURLClassLoader>)() -> new ModURLClassLoader(new URL[] { jarPath.toUri().toURL() }, getClass().getClassLoader()));
} catch (PrivilegedActionException ex) {
throw new ModNotLoadableException(ex);
}
Class<?> clazz = Class.forName(entryPoint, false, modUrlClassLoader);
if (!ECSMod.class.isAssignableFrom(clazz)) {
throw new ModNotLoadableException(clazz + " does not implement ECSMod");
}
this.ecsMod = (ECSMod)clazz.newInstance();
} catch (Exception ex) {
throw new ModNotLoadableException(ex);
}
}
#Override
protected void unload0() {
try {
modUrlClassLoader.close();
} catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}
#Override
protected ECSGame createGame0() {
ECSGame ecsGame = new ECSGame();
ecsMod.setupGame(ecsGame);
return ecsGame;
}
}
Which loads an untrusted JAR that has a class that implements ECSMod, I have confirmed that both the clazz and ecsMod belong to an instance of ModURLClassLoader.
Then the malicious code:
public final class UntrustedEvilMod implements ECSMod {
#Override
public void setupGame(final ECSGame game) {
System.exit(0);
}
}
Where ECSMod and ECSGame are classes that belong to the plugin (also called mod) API and reside in the original classloader.
I'm running this without a security manager, as I believe that this would be unnecessary in this context? As the ModURLClassLoader defines the security.
Why is this not working, meaning that it still causes the program to exit, whereas I would've wanted an AccessControlException?
I use spring framework to find the class and its methods and arguments dynamically.
these are the methods I use :
public List<Class> findMyTypes(String basePackage) throws IOException, ClassNotFoundException
{
ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourcePatternResolver);
List<Class> candidates = new ArrayList<Class>();
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + "/" + "**/*.class";
Resource[] resources = resourcePatternResolver.getResources(packageSearchPath);
for (Resource resource : resources) {
if (resource.isReadable()) {
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
if (isCandidate(metadataReader)) {
candidates.add(Class.forName(metadataReader.getClassMetadata().getClassName()));
}
}
}
return candidates;
}
public String resolveBasePackage(String basePackage) {
return ClassUtils.convertClassNameToResourcePath(SystemPropertyUtils.resolvePlaceholders(basePackage));
}
#SuppressWarnings({ "rawtypes", "unchecked" })
public boolean isCandidate(MetadataReader metadataReader) throws ClassNotFoundException
{
try {
Class c = Class.forName(metadataReader.getClassMetadata().getClassName());
if (c.getAnnotation(Controller.class) != null) {
return true;
}
}
catch(Throwable e){
}
return false;
}
I load the class which has got annotation #Controller. It is working fine but I want to load only the class not interface also how do I get the methods and the arguments of the class loaded.
EDIT :
This is how I get all the class names and try to get the methods name :
List classNames = hexgenClassUtils.findMyTypes("com.hexgen.*");
Iterator<Class> it = classNames.iterator();
while(it.hasNext())
{
Class obj = it.next();
System.out.println("Class :"+obj.toString());
cls = Class.forName(obj.toString());
Method[] method = cls.getMethods();
for (Method method2 : method) {
System.out.println("Method name : "+method2.toGenericString());
}
// TODO something with obj
}
The problem I face is class com.hexgen.api.facade.HexgenWebAPI here class is coming because of which I am not able to load the class dynamically and get the following exception.
java.lang.ClassNotFoundException: class com.hexgen.api.facade.HexgenWebAPI so how to solve it.
Kindly help me to find the solution.
Best Regards
try
Class c = Class.forName(metadataReader.getClassMetadata().getClassName());
if (!c.isInterface() && c.getAnnotation(Controller.class) != null) {
return true;
}
I am attempting to load classes dynamically into a component. I am using a file chooser to select the .JAR file that will be loaded and then a option pane to get the name of the class.
I have trawled the internet looking for how to convert a java file to a URL in order to load it in URLClassLoader and I have come up with:
File myFile = filechooser.getSelectedFile();
String className = JOptionPane.showInputDialog(
this, "Class Name:", "Class Name", JOptionPane.QUESTION_MESSAGE);
URL myUrl= null;
try {
myUrl = myFile.toURL();
} catch (MalformedURLException e) {
}
URLClassLoader loader = new URLClassLoader(myUrl);
loader.loadClass(className);
I am now getting a 'cannot find symbol' error for loading the URL into the URLClassLoader
I like the ClassPathHacker class mentioned in the answer by Zellus, but it's full of deprecated calls and bad practices, so here's a rewritten version that also caches the Classloader and the addUrl method:
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.io.IOException;
import java.io.File;
public class ClassPathHacker{
private static final Class<URLClassLoader> URLCLASSLOADER =
URLClassLoader.class;
private static final Class<?>[] PARAMS = new Class[] { URL.class };
public static void addFile(final String s) throws IOException{
addFile(new File(s));
}
public static void addFile(final File f) throws IOException{
addURL(f.toURI().toURL());
}
public static void addURL(final URL u) throws IOException{
final URLClassLoader urlClassLoader = getUrlClassLoader();
try{
final Method method = getAddUrlMethod();
method.setAccessible(true);
method.invoke(urlClassLoader, new Object[] { u });
} catch(final Exception e){
throw new IOException(
"Error, could not add URL to system classloader");
}
}
private static Method getAddUrlMethod()
throws NoSuchMethodException{
if(addUrlMethod == null){
addUrlMethod =
URLCLASSLOADER.getDeclaredMethod("addURL", PARAMS);
}
return addUrlMethod;
}
private static URLClassLoader urlClassLoader;
private static Method addUrlMethod;
private static URLClassLoader getUrlClassLoader(){
if(urlClassLoader == null){
final ClassLoader sysloader =
ClassLoader.getSystemClassLoader();
if(sysloader instanceof URLClassLoader){
urlClassLoader = (URLClassLoader) sysloader;
} else{
throw new IllegalStateException(
"Not an UrlClassLoader: "
+ sysloader);
}
}
return urlClassLoader;
}
}
ClassPathHacker.java found in this forum thread, is an option to load classes dynamically.
import java.lang.reflect.*;
import java.io.*;
import java.net.*;
public class ClassPathHacker {
private static final Class[] parameters = new Class[]{URL.class};
public static void addFile(String s) throws IOException {
File f = new File(s);
addFile(f);
}//end method
public static void addFile(File f) throws IOException {
addURL(f.toURL());
}//end method
public static void addURL(URL u) throws IOException {
URLClassLoader sysloader = (URLClassLoader)ClassLoader.getSystemClassLoader();
Class sysclass = URLClassLoader.class;
try {
Method method = sysclass.getDeclaredMethod("addURL",parameters);
method.setAccessible(true);
method.invoke(sysloader,new Object[]{ u });
} catch (Throwable t) {
t.printStackTrace();
throw new IOException("Error, could not add URL to system classloader");
}//end try catch
}//end method
}//end class
Take a look at this related question: How should I load Jars dynamically at runtime?
The constructor of URLClassLoader takes an array of URLs, not a single URL.
I rewrote this in scala in case anyone needs as it isn't 100% trivial :)
/*
* Class which allows URLS to be "dynamically" added to system class loader
*/
object class_path_updater {
val URLCLASSLOADER = classOf[URLClassLoader]
var urlClassLoader = getUrlClassLoader
var addUrlMethod = getAddUrlMethod
/*
* addFile - have to use reflection to retrieve and call class loader addURL method as it is protected
*/
def addFile(s: String) = {
val urlClassLoader = getUrlClassLoader
try {
val method = getAddUrlMethod
method.setAccessible(true)
val v = (new File(s)).toURI.toURL
invoke(urlClassLoader, method, Array[AnyRef](v))
def invoke(proxy: AnyRef, m: Method, args: Array[AnyRef]) = m.invoke(proxy, args: _*)
}
}
private def getAddUrlMethod: Method = {
if (addUrlMethod == null) addUrlMethod = URLCLASSLOADER.getDeclaredMethod("addURL", classOf[URL])
addUrlMethod
}
private def getUrlClassLoader: URLClassLoader = {
if (urlClassLoader == null) {
val sysLoader = ClassLoader.getSystemClassLoader
sysLoader match {
case x: URLClassLoader => urlClassLoader = sysLoader.asInstanceOf[URLClassLoader]
case _ => throw new IllegalStateException("Not a UrlClassLoader: " + sysLoader)
}
}
urlClassLoader
}
}
Despite warnings to drop my present course of action, I currently see no better way to solve my problem. I must generate Java code at runtime, then compile it, load it and reference it.
Problem is that the generated code imports code that has already been loaded by the system class loader (I suppose) - that is, code present in one of the jars on my classpath.
(I run inside a Tomcat 6 web container over Java 6.) You may ask yourselves why that is a problem - well I sure don't know - but fact is that I get compilation errors:
/W:/.../parser/v0.5/AssignELParser.java:6:
package com.xxx.yyy.zzz.configuration
does not exist
Following some examples off the internet I have defined the following classes:
class MemoryClassLoader extends ChainedAction {
private static final Logger LOG = Logger.getLogger(MemoryClassLoader.class);
private LoaderImpl impl;
private class LoaderImpl extends ClassLoader {
// The compiler tool
private final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
// Compiler options
private final Iterable<String> options = Arrays.asList("-verbose");
// DiagnosticCollector, for collecting compilation problems
private final DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
// Our FileManager
private final MemoryFileManager manager = new MemoryFileManager(this.compiler);
public LoaderImpl(File sourceDirectory) {
List<Source> list = new ArrayList<Source>();
File[] files = sourceDirectory.listFiles(new FilenameFilter() {
#Override
public boolean accept(File dir, String name) {
return name.endsWith(Kind.SOURCE.extension);
}
});
for (File file : files) {
list.add(new Source(file));
}
CompilationTask task = compiler.getTask(null, manager, diagnostics, options, null, list);
Boolean compilationSuccessful = task.call();
LOG.info("Compilation has " + ((compilationSuccessful) ? "concluded successfully" : "failed"));
// report on all errors to screen
for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
LOG.warn(diagnostic.getMessage(null));
}
}
#Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
synchronized (this.manager) {
Output output = manager.map.remove(name);
if (output != null) {
byte[] array = output.toByteArray();
return defineClass(name, array, 0, array.length);
}
}
return super.findClass(name);
}
}
#Override
protected void run() {
impl = new LoaderImpl(new File(/* Some directory path */));
}
}
class MemoryFileManager extends ForwardingJavaFileManager<JavaFileManager> {
final Map<String, Output> map = new HashMap<String, Output>();
MemoryFileManager(JavaCompiler compiler) {
super(compiler.getStandardFileManager(null, null, null));
}
#Override
public Output getJavaFileForOutput(Location location, String name, Kind kind, FileObject source) {
Output output = new Output(name, kind);
map.put(name, output);
return output;
}
}
class Output extends SimpleJavaFileObject {
private final ByteArrayOutputStream baos = new ByteArrayOutputStream();
Output(String name, Kind kind) {
super(URI.create("memo:///" + name.replace('.', '/') + kind.extension), kind);
}
byte[] toByteArray() {
return this.baos.toByteArray();
}
#Override
public ByteArrayOutputStream openOutputStream() {
return this.baos;
}
}
class Source extends SimpleJavaFileObject {
public Source(File file) {
super(file.toURI(), Kind.SOURCE);
}
#Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
StringBuilder sb = new StringBuilder("");
try {
File file = new File(uri);
FileReader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
sb = new StringBuilder((int) file.length());
String line = "";
while ((line = br.readLine()) != null) {
sb.append(line);
sb.append("\n");
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return sb.toString();
}
}
It seems that the inner class LoaderImpl by extending the ClassLoader class and by not calling an explicit super constructor should reference as its parent class loader the system class loader.
If it does so then why do I get the "runtime" compilation error - above? Why does it not find the code for the imported class?
Not sure if it can help, but have you tried to specify classpath explicitly?
getClassPath()
{
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
URL[] urls = ((URLClassLoader) classLoader).getURLs();
StringBuilder buf = new StringBuilder(1000);
buf.append(".");
String separator = System.getProperty("path.separator");
for (URL url : urls) {
buf.append(separator).append(url.getFile());
}
}
classPath = buf.toString();
and then
options.add("-classpath");
options.add(getClassPath());
I also can't see where do you pass LoaderImpl instance to the compiler. Shouldn't it be done explicitly?