Reputation: 632
I've got a really strange problem.
I'm using a URLClassLoader to dynamically import files from a directory. The code works fine if I use a literal string, and works fine if I use a variable to a literal string, but this isn't what I need.
package test;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
public class Test {
public static void main(String[] args) {
try {
File subfolder = new File("C:\\temp\\");
URL classUrl = subfolder.toURI().toURL();
URL[] classUrls = { classUrl };
URLClassLoader ucl = new URLClassLoader(classUrls);
for (File f : subfolder.listFiles()) {
String name = f.getName()
.substring(0, f.getName().lastIndexOf(".")).trim();
if (name.equals("TestClass"))
System.out.println(name);
try {
MyInterface de = (MyInterface) Class.forName("TestClass", true, ucl)
.newInstance();
de.printSomething();
} catch (ClassNotFoundException e) {
}
ucl.close();
}
} catch (MalformedURLException e) {
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
What I need is to be able to do this:
MyInterface de = (MyInterface) Class.forName(name, true, ucl).newInstance();
But it's not working even though "name" is a valid String and does equal "TestClass".
EDIT: I get the error:
java.lang.ClassNotFoundException: TestClass
at java.net.URLClassLoader$1.run(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Unknown Source)
at test.Test.main(Test.java:25)
What's wrong?
Upvotes: 4
Views: 478
Reputation: 4076
I guess this is because of the ucl.close() inside the for loop. I added some test if there are directories: the following class works and instanciate itself if declared in the root package, and if eclipse is configure to generate .class file in "bin" directory:
public class Toto {
public Toto(){
// this writes "Toto" in the console if the class is well instanciated
System.out.println("Toto");
}
public static void main(String[] args) {
try {
File subfolder = new File("bin");
URL classUrl = subfolder.toURI().toURL();
URL[] classUrls = { classUrl };
URLClassLoader ucl = new URLClassLoader(classUrls);
for (File f : subfolder.listFiles()) {
String fileName= f.getName();
int suffix = fileName.lastIndexOf('.');
if(f.isDirectory() || suffix==-1){
continue;
}
String name = fileName.substring(0, suffix);
try {
Class.forName(name, true, ucl).newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
ucl.close();
} catch (MalformedURLException e) {
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Upvotes: 4
Reputation: 703
It appears your issue has to do with the fact that your class being loaded has a package. When Java loads these classes, it expects to find the directory structure related to that package. So, the following code works:
try {
File subfolder = new File("/home/glen/TestClass");
URL classUrl = subfolder.toURI().toURL();
URL[] classUrls = { classUrl };
URLClassLoader ucl = new URLClassLoader(classUrls);
for (File f : subfolder.listFiles()[0].listFiles()) {
System.out.println(f.getName());
String name = f.getName()
.substring(0, f.getName().lastIndexOf(".")).trim();// "TestClass";
if (name.equals("TestClass"))
System.out.println(name);
try {
MyInterface de = (MyInterface) Class.forName("test." + name, true, ucl)
.newInstance();
de.printSomething();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ucl.close();
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Note how I am:
test.TestClass
, in the Class.forName
methodIn essence, the URLClassLoader requires a JAR-like directory structure, like test/TestClass.class
, while having a URL root which contains the directory structure.
My working theory is that you are not just changing the name variable to a string literal, as when I do that it still works fine. Double check you're not changing anything else. Either way, I hope this points you in the right direction.
Upvotes: 4
Reputation: 311052
What's wrong?
The first thing that's wrong is that this isn't the real code. This code catches and ignores ClassNotFoundException
:
} catch (ClassNotFoundException e) {
}
So it cannot possibly produce the output shown.
The second thing that's wrong is that when this is corrected, the code works as expected.
Cannot reproduce.
Clearly you weren't running the code you thought you were running. Java simply does not behave as claimed.
Upvotes: 3
Reputation: 3699
Instead of
MyInterface de = (MyInterface) Class.forName(name, true, ucl).newInstance();
use
MyInterface de = (MyInterface) Class.forName(name + "Class", true, ucl).newInstance();
works for me.
Upvotes: 2