how can I dynamically load a class in Java with two parameters which are the absolute filepath of the class file and the name of the method I wish to call?
eg path: c:\foo.class
method: print()
I am just interested in the basics as a simple cmd line tool. A code example would b appreciated.
cheers hoax
Use URLClassLoader. The name of the method is irrelevant. You must pass the root directory of your package to the class loader. Then you can use the fully qualified class name (package + class name) in Class.forName() to get the Class instance. You can use the normal reflection calls to create an instance of this class and call methods on it.
To make your life more simple, have a look at commons-beanutils. It makes invoking methods much more simple.
Check out this example:
// Create a File object on the root of the directory containing the class file
File file = new File("c:\\myclasses\\");
try {
// Convert File to a URL
URL url = file.toURL(); // file:/c:/myclasses/
URL[] urls = new URL[]{url};
// Create a new class loader with the directory
ClassLoader cl = new URLClassLoader(urls);
// Load in the class; MyClass.class should be located in
// the directory file:/c:/myclasses/com/mycompany
Class cls = cl.loadClass("com.mycompany.MyClass");
} catch (MalformedURLException e) {
} catch (ClassNotFoundException e) {
}
After this, you could do something like this to first create a new instace using the default constructor and invoking the method "print" without arguments:
Object object = cls.newInstance();
cls.getMethod("print").invoke(object);
Related
I've got a classloader problem with Java 9.
This code worked with previous Java versions:
private static void addNewURL(URL u) throws IOException {
final Class[] newParameters = new Class[]{URL.class};
URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Class newClass = URLClassLoader.class;
try {
Method method = newClass.getDeclaredMethod("addNewURL", newParameters );
method.setAccessible(true);
method.invoke(urlClassLoader, new Object[]{u});
} catch (Throwable t) {
throw new IOException("Error, could not add URL to system classloader");
}
}
From this thread I learned that this has to be replaced by something like this:
Class.forName(classpath, true, loader);
loader = URLClassLoader.newInstance(
new URL[]{u},
MyClass.class.getClassLoader()
MyClass is the class I'm trying to implement the Class.forName() method in.
u = file:/C:/Users/SomeUser/Projects/MyTool/plugins/myNodes/myOwn-nodes-1.6.jar
String classpath = URLClassLoader.getSystemResource("plugins/myNodes/myOwn-nodes-1.6.jar").toString();
For some reason - I really can't figure out, why - I get a ClassNotFoundException when running Class.forName(classpath, true, loader);
Does someone know what I'm doing wrong?
From the documentation of the Class.forName(String name, boolean initialize, ClassLoader loader) :-
throws ClassNotFoundException - if the class cannot be located by the specified class loader
Also, note the arguments used for the API includes the name of the class using which the classloader returns the object of the class.
Given the fully qualified name for a class or interface (in the same format returned by getName) this method attempts to locate, load, and link the class or interface.
In your sample code, this can be redressed to something like :
// Constructing a URL form the path to JAR
URL u = new URL("file:/C:/Users/SomeUser/Projects/MyTool/plugins/myNodes/myOwn-nodes-1.6.jar");
// Creating an instance of URLClassloader using the above URL and parent classloader
ClassLoader loader = URLClassLoader.newInstance(new URL[]{u}, MyClass.class.getClassLoader());
// Returns the class object
Class<?> yourMainClass = Class.forName("MainClassOfJar", true, loader);
where MainClassOfJar in the above code shall be replaced by the main class of the JAR myOwn-nodes-1.6.jar.
I want to run the constructor of the Main.class in the package Test2, located in the folder C:\classes\
This is the code I'm using. It throws a class not found exception when it tries to turn it into a class. And then once it's part of the class object, will the constructor automatically be run, or do I have to instance it somehow? Test2 is inputted into this code as text.
if (Main.os.equals("Windows"))
{
String path = "C:\\classes\\";
}
else
{
String path = "~/classes/";
}
File file = new File(path);
try
{
URL url = file.toURI().toURL();
URL[] urls = new URL[]{url};
Main.print("Stage 1");
ClassLoader cl = new URLClassLoader(urls);
Main.print("Stage 2");
Class cls = cl.loadClass(text + ".Main");
Main.print(text + " was loaded into memory.");
close();
}
catch (MalformedURLException e)
{
e.printStackTrace();
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
I suspect your problem is one of the following:
file doesn't exist or hasn't been properly specified. Check via file.exists()
Your class file is not located in the correct directory. If the package declaration for the Main class is package Test2; then your class file must be in the following location: C:\classes\Test2\Main.class.
If Main is nested class, then you will need to refer to the enclosing class when loading it, eg cl.loadClass("Test2.EnclosingClass$Main");
My guess it that your problem is number 2! :)
Good luck.
Oh, and yes, you'll need to create an instance of your object if you want the constructor to be called: clazz.newInstance() is the simplest method for no-args constructors.
Can you post the exact error message.
But here is how I execute a main method of using a class loader
urlLoader = new URLClassLoader(urls);
Class runClass = urlLoader.loadClass(classToRun);
System.out.println("Starting Program !!!");
Object[] arguments = new Object[]{args};
Method mainMethod = runClass.getMethod("main", new Class[] {args.getClass()});
mainMethod.invoke(null, arguments);
Note: classToRun will be the full package/class definition
i.e. net.sf.RecordEditor.edit.FullEditor
Note: I use it to load from jar files, it will be similar for directories
It is taken from the run class here
http://record-editor.svn.sourceforge.net/viewvc/record-editor/Source/RecordEditor/src/net/sf/RecordEditor/utils/Run.java?revision=65&view=markup
An example of calling the class is here
http://record-editor.svn.sourceforge.net/viewvc/record-editor/Source/RecordEditor/src/net/sf/RecordEditor/RunFullEditor.java?revision=65&view=markup
I'm trying to load dynamically a class contained in a .jar file. I know the whole class name and I know for sure that the class implements the interface AlgorithmClass.
My code looks like this:
addURLToSystemClassLoader(dir.toURI().toURL());
Class cl = Class.forName(algorithm.getClassName());
AlgorithmClass algorithmClass = (AlgorithmClass)cl.newInstance();
Where dir is the File object of the .jar file and addURLToSystemClassLoader(URL) looks like this:
private void addURLToSystemClassLoader(URL url) throws IntrospectionException {
URLClassLoader systemClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Class<URLClassLoader> classLoaderClass = URLClassLoader.class;
try {
Method method = classLoaderClass.getDeclaredMethod("addURL", new Class[]{URL.class});
method.setAccessible(true);
method.invoke(systemClassLoader, new Object[]{url});
} catch (Throwable t) {
t.printStackTrace();
throw new IntrospectionException("Error when adding url to system ClassLoader ");
}
}
I checked and the URL is being added to the class loader.
When I try to get the Class object I get the error:
SEVERE: javax.servlet.ServletException: java.lang.ClassNotFoundException: id3.Algorithm
(id3.Algorithm is the full name of the class I'm trying to load)
I've tried creating a new ClassLoader like below:
ClassLoader cload = new URLClassLoader(new URL[]{dir.toURI().toURL()}, ClassLoader.getSystemClassLoader());
Class cl = Class.forName(algorithm.getClassName(), false, cload);
AlgorithmClass algorithmClass = (AlgorithmClass)cl.newInstance();
But then I get the error:
java.lang.NoClassDefFoundError: lib/algorithm/AlgorithmClass
I've tried creating a new URLClassLoader with all the URLs that the system class loader has but the effect was the same.
The "worst" part of this is that both ways are working perfectly fine on the jUnit test that I have for testing this part of my code.
I'm using Glassfish 3.1.1 as my app server.
dir shouldn't contain 'lib'.
Try this:
ClassLoader cload = new URLClassLoader(new URL[]{dir.toURI().toURL()}, Thread.currentThread().getContextClassLoader());
Class cl = Class.forName(algorithm.getClassName(), true, cload);
AlgorithmClass algorithmClass = (AlgorithmClass)cl.newInstance();
You have class-loading issue. You shoud be aware that your addURLToSystemClassLoader() is actually the heck...
Put your jar to the classpath. Use Class.forName() idiom. If it fails use version that receives ClassLoader as parammeter namely
public static Class<?> forName(String name, boolean initialize,
ClassLoader loader)
and path Thread.currentThread().getContextClassLoader() as ClassLoader parameter.
See also my another answer below.
I want to create a new ClassLoader everytime my method is called.
So I can reload a class without exiting my program.
A way how I can update a class loaded by ClassLoader would also be a solution.
How can I achieve that?
I found a good explained answer here:
http://www.exampledepot.com/egs/java.lang/reloadclass.html
The important thing is to have two binary folders, in my case:
one for the testcases and one for the program source.
Quote:
URL[] urls = null;
try {
// Convert the file object to a URL
File dir = new File(System.getProperty("user.dir")
+File.separator+"dir"+File.separator);
URL url = dir.toURL(); // file:/c:/almanac1.4/examples/
urls = new URL[]{url};
} catch (MalformedURLException e) {
}
try {
// Create a new class loader with the directory
ClassLoader cl = new URLClassLoader(urls);
// Load in the class
Class cls = cl.loadClass("MyReloadableClassImpl");
saw this ? ClassLoader Load / Reload Example
I think this blog can satisfy your requirement.
I got some java-byte-code (so compiled java-source) which is generated in my program. Now I want to load this byte-code into the currently running Java-VM and run a specific function. I'm not sure how to accomplish this, I digged a little bit into the Java Classloaders but found no straight way.
I found a solution which takes a class-file on the harddisk, but the bytecode I got is in a Byte-Array and I dont want to write it down to the disk but use it directly instead.
Thanks!
you need to write a custom class loader that overloads the findClass method
public Class findClass(String name) {
byte[] b = ... // get the bytes from wherever they are generated
return defineClass(name, b, 0, b.length);
}
If the byte code is not on the classpath of the running program, you can use URLClassLoader. From http://www.exampledepot.com/egs/java.lang/LoadClass.html
// Create a File object on the root of the directory containing the class file
File file = new File("c:\\myclasses\\");
try {
// Convert File to a URL
URL url = file.toURL(); // file:/c:/myclasses/
URL[] urls = new URL[]{url};
// Create a new class loader with the directory
ClassLoader cl = new URLClassLoader(urls);
// Load in the class; MyClass.class should be located in
// the directory file:/c:/myclasses/com/mycompany
Class cls = cl.loadClass("com.mycompany.MyClass");
} catch (MalformedURLException e) {
} catch (ClassNotFoundException e) {
}