Reputation: 1809
So, I have a .class
file, along with its absolute path, and I need to know how you would go about executing that .class
file from inside Java. It would be great if I were able to get a Class
object from it, too.
I'm aware of the loadClass
method in ClassLoader
, but it requires the file's "binary name." I'm not sure if it's possible to get an external .class
file's binary name, but if you can, that would work greatly! If not, however, is there any other way to execute or get an instance of an external .class
file?
/*For those of us who work better with examples..
Let's say I have a .class file located at C:/Users/USER/Desktop. So..*/
String absolutePath = "C:/Users/USER/Desktop/FILE.class";
/*Now, having that, how would I get an instance of that class, or,
at least, execute it?*/
Upvotes: 3
Views: 2677
Reputation: 413
The trick is going to be accessing ClassLoader's defineClass methods. Let's say you wanted to dynamically load a random class file that implemented a known interface (If you don't know the interface you would use reflection api to find and call methods).
package com.example.fileclassloader;
public interface Dynamo {
public Integer beDynamic(String s);
}
Somewhere is a compiled class that implements that interface. It may look something like:
public class Sample implements com.example.fileclassloader.Dynamo {
public Integer beDynamic(String s) {
System.out.println(String.format("The value is: %s", s));
return s.length();
}
}
Now to use it we need to extend a class loader so we can access the defineClass method. This one will just take in the filename, load the bytes and create the instance:
package com.example.fileclassloader;
import java.io.File;
import java.io.IOException;
import java.security.SecureClassLoader;
public class MyDynamoClassLoader extends SecureClassLoader {
public Object createObjectFromFile(String fileName) throws
InstantiationException, IOException, IllegalAccessException {
File file = new File(fileName);
byte[] classBytes =
org.apache.commons.io.FileUtils.readFileToByteArray(file);
Class<?> clazz = defineClass(null, classBytes, 0, classBytes.length);
return clazz.newInstance();
}
}
Now we need to use the dynamically loaded class instance. We cast it to the interface we are expecting it to conform to, and use it like any other instance of the interface:
package com.example.fileclassloader;
import java.io.FileNotFoundException;
import java.io.IOException;
public class App {
public static void main() throws FileNotFoundException, IOException,
InstantiationException, IllegalAccessException {
String fname = "target/classes/com/example/fileclassloader/Sample.class";
MyDynamoClassLoader loader = new MyDynamoClassLoader();
Dynamo dynamo = (Dynamo) loader.createObjectFromFile(fname);
Integer i = dynamo.beDynamic("Testing");
System.out.println(String.format("Dynamo (%s) returned %d", fname, i));
}
}
And for good measure, here is the pom.xml file for building it:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>fileclassloader</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
</dependencies>
</project>
Upvotes: 5