ClassNotFoundException when using dynamic classloader - java

It's a project downloaded from Web and I just changed the path to find the class which I want to make it load dynamically.Here are the codes in which I try to load the class on runtime.But I got a ClassNotFoundException eventually:
private static IExample newInstanceWithThrows() throws InstantiationException, IllegalAccessException, ClassNotFoundException {
URLClassLoader tmp =
new URLClassLoader(new URL[] {getClassPath()}) {
public Class<?> loadClass(String name)
throws ClassNotFoundException {
if ("example.Example".equals(name)
|| "example.Leak".equals(name))
return findClass(name);
return super.loadClass(name);
}
};
return (IExample) tmp.loadClass("example.Example")
.newInstance();
}
private static URL getClassPath() {
String dir = "/Users/longtuan/develop/rjc2011/classes/";
try {
//return new URL(dir);
File path = new File(dir);
return path.toURL();
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
And the path to class example.Example is:
/Users/longtuan/develop/java/rjc2011/classes/example
And the run command I used is:
java -classpath ./bin example.Main
Current directory is:
/Users/longtuan/develop/java/rjc2011
All the things of current directory are like this:
Example is the directory in which I put all the java files.I place the compiled class file in directory bin except the class example.Example which is put in classes lonely.
Above are all the informations I can give, thanks for any help.

Related

Dynamically loading and instantiating a .class that is not in the classpath

I have two java projects MASTER and PLUGIN. PLUGIN has dependencies to MASTER and its intent is to extend a class found in MASTER, called SCRIPT.
Once I have declared a SCRIPT (myScript), I want to move the .class file to a folder that MASTER can access. I want MASTER to dynamically load and instantiate that class as a SCRIPT.
I've looked for quite a bit and tried different solutions, but I always get a ClassNotFoundException exception.
I would prefer to do this without passing arguments to the JVM at startup.
Is it even possible? This is my current solution: "currentPath" is "etc/etc/myScript.class
try {
OUT.ln("initiating script " + currentPath);
File file = new File(currentPath);
File parent = file.getParentFile();
String name = file.getName().split(".class")[0];
// Convert File to a URL
URL url = parent.toURI().toURL();
URL[] urls = new URL[]{url};
// Create a new class loader with the directory
#SuppressWarnings("resource")
ClassLoader cl = new URLClassLoader(urls);
current = (SCRIPT) cl.loadClass("main.script." + name).newInstance();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Unable to load script " + currentPath);
}
if the class you want to load is defined within a package like:
main.script.myScript
and you want to load this class from a folder like c:/myclasses,
then you have to put this class to c:/myclasses/main/script/myScript.class
and then instantate the classloader with the basefolder like:
URL[] urls = new URL[]{new URL("file://c:/myclasses")};
ClassLoader cl = new URLClassLoader(urls);
then the class can be loaded by using the qualified class name:
cl.loadClass("main.script.myScript").getDeclaredConstructor().newInstance()
if you want to keep the class at a specific folder without considering the package structure you could do something like this:
public static void main(String[] args) {
try {
File file = new File("etc/etc/myScript.class");
String className = file.getName().split(".class")[0];
String packageName = "main.script.";
byte[] bytes = Files.readAllBytes(Path.of(file.getPath()));
MyClassLoader myClassLoader = new MyClassLoader(Thread.currentThread().getContextClassLoader());
Object o = myClassLoader.getClass(packageName+className, bytes).getDeclaredConstructor().newInstance();
System.out.println(o);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Unable to load script ");
}
}
public static class MyClassLoader extends ClassLoader {
public MyClassLoader(ClassLoader parent) {
super(parent);
}
public Class<?> getClass(String name, byte[] code) {
return defineClass(name, code, 0, code.length);
}
}

How to load class files into a project to create an object

With the following code snippet, I am trying to load some class files into my project to create an object. Unfortunately, it seems that something is missing, because there are no classes loaded. What is it?
private static void myClassloader() throws Exception
{
File file = new File(pathGeneratedClasses);
try
{
#SuppressWarnings("deprecation")
URL url = file.toURL();
URL[] urls = new URL[]{url};
ClassLoader sqlQuery = new URLClassLoader(urls);
Class myClass = sqlQuery.loadClass("de.cimt.jaxb.JaxCodeGen");
}
catch (Exception e)
{
System.out.println(e.toString());
}
}
sqlQuery.loadClass() will be returning the class you requested for, try assigning the returned value to something.
If no class is found then ClassNotFoundException will be thrown.

Using an URLClassLoader inside Jetty

I am developing a wicket application which is running on jetty. My application should be able to load plugins from jar-files.
Thus I created a URLClassLoader which should load the plugin classes.
As a standard Java-application everything works, but when I want to load plugins on the server I get following errors: http://pastebin.com/e2JRAYTr
The Module interface that can not be found is defined in another project, but if I output the class-name in Wickets init() method like this
System.out.println(Module.class.getName())`
I get no error. So I think the other project is loaded correctly by Maven but there are issues with my custom jar-classloader.
The classloaders constructor where the action happens looks like this:
public WorkableLoader(final File jarFile) throws IOException, ClassNotFoundException, InstantiationException,
IllegalAccessException {
final URL[] urls = new URL[] { jarFile.toURI().toURL() };
classLoader = new URLClassLoader(urls);
final Class<?> cls = loadWorkableClass(jarFile);
workable = (Workable) cls.newInstance();
}
private Class<?> loadWorkableClass(final File jar) throws ClassNotFoundException, IOException {
try (final JarFile jarFile = new JarFile(jar)) {
final Enumeration<JarEntry> jarEntries = jarFile.entries();
while (jarEntries.hasMoreElements()) {
final JarEntry jarEntry = jarEntries.nextElement();
if (isClassFile(jarEntry.getName())) {
final String className = jarEntry.getName().replace("/", ".").replace(".class", "");
final Class<?> cls = classLoader.loadClass(className);
for (final Class<?> iface : cls.getInterfaces()) {
if (iface.equals(Module.class) || iface.equals(Bundle.class)) {
return cls;
}
}
}
}
} catch (final IOException e) {
throw e;
}
throw new ClassNotFoundException("Es konnte keine Workable-Klasse gefunden werden.");
}
The method isClass() just checks if the file ends with .class.
The last error of my code is at com.siemens.importer.workables.WorkableLoader.loadWorkableClass(WorkableLoader.java:137). Line 137 is the line
final Class<?> cls = classLoader.loadClass(className); of the loadWorkableClass() method. So how can I load classes with a custom classloader on a
jetty server?
Sorry for the huge output and thanks in advance!

Loading jars at runtime

I am trying to add jar file to classpath at runtime. I use this code
public static void addURL(URL u) throws IOException {
URLClassLoader sysloader = (URLClassLoader) ClassLoader
.getSystemClassLoader();
Class<URLClassLoader> sysclass = URLClassLoader.class;
try {
Method method = sysclass.getDeclaredMethod("addURL", parameters);
method.setAccessible(true);
method.invoke(sysloader, new Object[] { u });
System.out.println(u);
} catch (Throwable t) {
t.printStackTrace();
throw new IOException("Error");
}
}
System out prints this url:
file:/B:/Java/Tools/mysql-connector-java-5.1.18/mysql-connector-java-5.1.18/mysql-connector-java-5.1.18-bin.jar
I was check this path carefully, this jar exist. Even this test show that com.mysql.jdbc.
Driver class exists.
javap -classpath "B:\Java\Tools\mysql-connector-java-5.1.18\
mysql-connector-java-5.1.18\mysql-connector-java-5.1.18-bin.jar" com.mysql.jdbc.
Driver
Compiled from "Driver.java"
public class com.mysql.jdbc.Driver extends com.mysql.jdbc.NonRegisteringDriver i
mplements java.sql.Driver{
public com.mysql.jdbc.Driver() throws java.sql.SQLException;
static {};
}
But I still get java.lang.ClassNotFoundException when I use this Class.forName(driver).
What is wrong with this code?
The URL is ok, nevertheless you try to load a jar from classpath, so it means that yo need to have the file in cp first.
In your case you want to load a jar that is not in classpath so you have to use
URLClassLoader and for JAR you can use also the JARClassLoader
If you want some sample lesson on it:
http://docs.oracle.com/javase/tutorial/deployment/jar/jarclassloader.html
Here a sample I ran by myself see if helps you. It search the Logger class of Log4j that is not in my classpath, of course i got exception on invocation of the constructor since i did not pass the right params to the constructor
package org.stackoverflow;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
public class URLClassLoaderSample
{
public static void main(String[] args) throws Exception
{
File f = new File("C:\\_programs\\apache\\log4j\\v1.1.16\\log4j-1.2.16.jar");
URLClassLoader urlCl = new URLClassLoader(new URL[] { f.toURL()},System.class.getClassLoader());
Class log4jClass = urlCl.loadClass("org.apache.log4j.Logger");
log4jClass.newInstance();
}
}
Exception in thread "main" java.lang.InstantiationException: org.apache.log4j.Logger
at java.lang.Class.newInstance0(Class.java:357)
at java.lang.Class.newInstance(Class.java:325)
at org.stackoverflow.URLClassLoaderSample.main(URLClassLoaderSample.java:19)
Exception due to the wrong invocation, nevertheless at this stage we already found the class
Ok try the alternative approach with DataSource and not directly the Driver
Below is the code (working with oracle driver, i don't have my sql db, but the properties are the same)
Generally using the DataSource interface is the preferred approach since JDBC 2.0
The DataSource jar was not in the classpath neither for the test below
public static void urlCLSample2() throws Exception
{
File f = new File("C:\\_programs\\jdbc_drivers\\oracle\\v11.2\\ojdbc6.jar");
URLClassLoader urlCl = new URLClassLoader(new URL[] { f.toURL() }, System.class.getClassLoader());
// replace the data source class with MySQL data source class.
Class dsClass = urlCl.loadClass("oracle.jdbc.pool.OracleDataSource");
DataSource ds = (DataSource) dsClass.newInstance();
invokeProperty(dsClass, ds, "setServerName", String.class, "<put your server here>");
invokeProperty(dsClass, ds, "setDatabaseName", String.class, "<put your db instance here>");
invokeProperty(dsClass, ds, "setPortNumber", int.class, <put your port here>);
invokeProperty(dsClass, ds, "setDriverType",String.class, "thin");
ds.getConnection("<put your username here>", "<put your username password here>");
System.out.println("Got Connection");
}
// Helper method to invoke properties
private static void invokeProperty(Class dsClass, DataSource ds, String propertyName, Class paramClass,
Object paramValue) throws Exception
{
try
{
Method method = dsClass.getDeclaredMethod(propertyName, paramClass);
method.setAccessible(true);
method.invoke(ds, paramValue);
}
catch (Exception e)
{
throw new Exception("Failed to invoke method");
}
}

ClassNotFound exception when extracting a class from a jar

I've been unsuccessfully trying to get a class from a .jar file. The .jar is located at C:\CTF.jar and contains a .class file CaptureTheFlagRules in a folder named CTF. The following code does not work:
try {
File jarFile = new File("C:\\CTF.jar");
URLClassLoader urlClassLoader = URLClassLoader.newInstance(new URL[]
{ jarFile.toURI().toURL() }, getClass.getClassLoader());
Class<?> unknownClass = Class.forName("CaptureTheFlagRules",
true, urlClassLoader);
....
} catch (MalformedURLException e) {
} catch (ClassNotFoundException e) {
}
The code throughs a ClassNotFoundException at the forName() call. What do I need to do to get my class?
Try:
Class<?> unknownClass = Class.forName("CTF.CaptureTheFlagRules",
true, urlClassLoader);
If it's in the CTF folder, it's probably in the CTF package.

Categories

Resources