from there, i using class loader to identified class from other directory
File dir=new File ("D:\\dirclass")
fulldir = new File (dir+"\\myclass");
filename = new StringTokenizer(fulldir.getName(), ".").nextToken();
URL[] checkclass =
{
dir.toURI().toURL()
};
URLClassLoader urlcl = new URLClassLoader(checkclass);
Class cls = urlcl.loadClass(filename);
this is worked if class without package.
but if class with package, failed to running.
Exception in thread "main" java.lang.NoClassDefFoundError: packclass (wrongname: dirclass\packclass)
is there any other way ?
You have to specify the fully qualified names of classes to the ClassLoader, for example:
Class cls = urlcl.loadClass("com.mypackage.MyClass");
Related
I have a java application which was developed in Eclipse.
There is a folder on the system which contains a lot of ".java" files. These ".java" files are classes which some user has written. I wish to load all these java classes and compile them inside my java application.
Another property of all the ".java" files are that all the classes written inside extend a class which is inside my original application.
I used the following to read and compile all the classes.
File parentFile = new File(rulesDir + "\\");
String fileName = rulesDir + "\\" + ruleName + ".java";
File ruleFile = new File(fileName);
// Compile source file.
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
compiler.run(null, null, null, ruleFile.getPath());
// Load and instantiate compiled class.
URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { parentFile.toURI().toURL() });
Class<? extends AbstractRule> cls = (Class<? extends AbstractRule>)Class.forName(ruleName, true, classLoader);
If I run the above code inside Eclipse, it works fine. When I run the application as a jar from elsewhere, it throws an ClassNotFoundException for the line
Class<? extends AbstractRule> cls = (Class<? extends AbstractRule>)Class.forName(ruleName, true, classLoader);
Why is this happening? What is different that it executes in Eclipse and doesn't via command line?
From the documentation for Class.forName
name - fully qualified name of the desired class
So, in order to get that fully qualified class name, you need to manipulate your rulesDir variable to replace the backslashes with periods, then prepend that to your ruleName variable, combined with another period, to get the fully qualified class name. Then you'll be able to use the ClassLoader to load the class. The fully qualified name is required so that the ClassLoader can find your resource from the root of your classpath.
NB I make the assumption that your rulesDir is a relative path from the base of your classpath. If it is not, then you'll have extra manipulation to do here
See code manipulation below:
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
import rules.AbstractRule;
public class MainApp {
public static void main(String[] args) {
try {
System.out.println("Test");
// NB Amended here to now take project root, relative path to rules directory and class name. So that compilation can take place based on the absolute path and class loading from the relative one.
compile("C:\\Media\\Code\\manodestra_java\\src\\tmp", "rules", "TestRule");
} catch (Exception e) {
e.printStackTrace();
}
}
private static void compile(String projectRoot, String rulesDir, String ruleName) throws Exception {
File parentFile = new File(projectRoot + "\\" + rulesDir + "\\");
System.out.println(parentFile);
String fileName = parentFile.getCanonicalPath() + "\\" + ruleName + ".java";
File ruleFile = new File(fileName);
System.out.println(ruleFile);
// Compile source file.
System.out.println("Compiling...");
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
compiler.run(null, null, null, ruleFile.getPath());
// Load and instantiate compiled class.
System.out.println("Loading class...");
URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { parentFile.toURI().toURL() });
System.out.println("Class Loader: " + classLoader);
ruleName = rulesDir.replace("\\", ".") + "." + ruleName;
Class<? extends AbstractRule> clazz = (Class<? extends AbstractRule>)Class.forName(ruleName, true, classLoader);
System.out.println(clazz);
}
}
For the sake of my testing, this class was defined in the default package and I created a rules directory below that level to contain my subclasses of AbstractRule. So, rules.TestRule was my fully qualified path to my class name. But, yours could be...
com.example.testapplication.rules.TestRule, etc.
And that's what would be required in Class.forName. There's a path to your classpath root, then the relative path from there to your java files (which is equivalent to the package of your classes), then the actual class names under that package path.
I need to load the Client.class using an ClassLoader .
When I use this code:
ClassLoader clientClassLoader = new URLClassLoader(
new URL[] { new File("client.jar").toURL() });
Class<?> clientClass = clientClassLoader.loadClass("pkhonor.Client");
I'm getting java.lang.ClassNotFoundException: /pkhonor/Client.
How should i Fix this problem?
I know that we can load classes dynamically by using custom class loaders.
But here my problem is my Class itself is depends upon other classes
My task is to get PigServer object .So I have used following code to load PigServer class
_pigServerClass = _classLoader.loadClass("org.apache.pig.PigServer");
But here PigServer class itself is depends upon so many other classes.
So when i am trying to get instance of PigServer class then it is showing following errors
java.lang.ClassNotFoundException: org.apache.commons.logging.LogFactory
java.lang.ClassNotFoundException:org.apache.log4j.AppenderSkeleton
etc..
Can anyone tell how to solve this?
There seems to be a misunderstanding. If you have all the jars required in a folder, say "lib", you can for example set up a class loader like this:
File libs = new File("lib");
File[] jars = libs.listFiles(new FileFilter() {
public boolean accept(File pathname) {
return pathname.getName().toLowerCase().endsWith(".jar");
}
});
URL[] urls = new URL[jars.length];
for (int i=0; i<jars.length; i++) {
urls[i] = jars[i].toURI().toURL();
}
ClassLoader uc = new URLClassLoader(urls,this.getClass().getClassLoader());
Class<?> pigServerClz = Class.forName("org.apache.pig.PigServer", false, uc);
Object pigServer = pigServerClz.newInstance();
// etc...
How you created your ClassLoader?
Did you specified another "parent" classloader, on wich classloading can be delegated?
the problem is next: i took the base classLoader code from here. but my classLoader is specific from a point, that it must be able to load classes from a filesystem(let's take WinOS), so in classLoader must be some setAdditionalPath() method, which sets a path(a directory on a filesystem), from which we'll load class(only *.class, no jars). here is code, which modifies the loader from a link(you can see, that only loadClass is modified), but it doesn't work properly:
public void setAdditionalPath(String dir) {
if(dir == null) {
throw new NullPointerException("");
}
this.Path = dir;
}
public Loader(){
super(Loader.class.getClassLoader());
}
public Class loadClass(String className) throws ClassNotFoundException {
if(Path.length() != 0) {
File file = new File(Path);
try {
// Convert File to an URL
URL url = file.toURL();
URL[] urls = new URL[]{url};
// Create a new class loader with the directory
ClassLoader cl = new URLClassLoader(urls);
ClassLoader c = cl.getSystemClassLoader();
Class cls = c.loadClass(className);
return cls;
} catch (MalformedURLException e) {
} catch (ClassNotFoundException e) {
}
}
return findClass(Path);
}
I'd grateful if anyone helps :)
You can just use framework provided java.net.URLClassLoader. No need to write your own. It supports loading of classes from directories and JAR files.
Any URL that ends with a '/' is assumed to refer to a directory.
Otherwise, the URL is assumed to refer to a JAR file which will be
opened as needed.
It also supports a parent class loader. If this class loader does not suite your requirements, perhaps you can specify in more detail what you need. And in any case, you can look at the source and derive your own class loader class based on that.
Here is a short working snippet of code that should demostrate how to load a class by name from a URLClassLoader:
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
// This URL for a directory will be searched *recursively*
URL classes =
new URL( "file:///D:/code/myCustomClassesAreUnderThisFolder/" );
ClassLoader custom =
new URLClassLoader( new URL[] { classes }, systemClassLoader );
// this class should be loaded from your directory
Class< ? > clazz = custom.loadClass( "my.custom.class.Name" );
// this class will be loaded as well, because you specified the system
// class loader as the parent
Class< ? > clazzString = custom.loadClass( "java.lang.String" );
What would be a good way to dynamically load java class files so that a program compiled into a jar can read all the class files in a directory and use them, and how can one write the files so that they have the necessary package name in relation to the jar?
I believe it's a ClassLoader you're after.
I suggest you start by looking at the example below which loads class files that are not on the class path.
// 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.toURI().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) {
}
Class myclass = ClassLoader.getSystemClassLoader().loadClass("package.MyClass");
or
Class myclass = Class.forName("package.MyClass");
or loading the class from different folder which is not in the classpath:
File f = new File("C:/dir");
URL[] cp = {f.toURI().toURL()};
URLClassLoader urlcl = new URLClassLoader(cp);
Class myclass = urlcl.loadClass("package.MyClass");
For further usage of the loaded Class you can use Reflection if the loaded Class is not in your classpath and you can not import and cast it. For example if you want to call a static method with the name "main":
Method m = myclass.getMethod("main", String[].class);
String[] args = new String[0];
m.invoke(null, args); // invoke the method
If you add a directory to your class path, you can add classes after the application starts and those classes can be loaded as soon as they have been written to the directory.