Explicit loading - java.lang.ClassLoader - java

In first case, For explicit loading of test.ClassLoaderTest using below code,
public ClassLoaderTest{
public static void main(String[] args){
.....
Class.forName("test.ClassLoaderTest", true,
ClassLoaderTest.class.getClassLoader().getParent());
....
}
findClass() method of Launcher$ExtClassLoader instance gets invoked to load test.ClassLoaderTest with below error due to visibility principle,
java.lang.ClassNotFoundException: test.ClassLoaderTest
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at sun.misc.Launcher$ExtClassLoader.findClass(Launcher.java:229)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:247)
at test.ClassLoaderTest.main(ClassLoaderTest.java:29)
In second case, On explicit loading of test.ClassLoaderTest1, using
public ClassLoaderTest{
public static void main(String[] args){
.....
Class.forName("test.ClassLoaderTest1");
....
}
loadClass() method of Launcher$AppClassLoader instance is ultimately used to load test.ClassLoaderTest1 class,
where test.ClassLoaderTest1 is a wrong class file that lead to below error,
java.lang.ClassNotFoundException: test.ClassLoaderTest1
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at test.ClassLoaderTest1.main(ClassLoaderTest.java:16)
In both cases, class loading job is done by java.net.URLClassLoader.findClass()
Class.forName() internally invokes getClassLoader() to know the class loader that already loaded the class.
In second case, When Class gets a class loader instance(of type Launcher$AppClassLoader) by calling
ClassLoader cl = getClassLoader0(); to invoke the class loader instance again.
Is java.lang.ClassLoader mainly used for sub-classing custom class loader? that load classes not available in CLASSPATH but from network source etc...

From the Javadoc,
public **abstract** class ClassLoader
extends Object
There are different ClassLoader implementations that use different strategies for locating and reading the byte streams that compose a class.

Related

Unable to load class(C:\com\scheduler\jobs) when class has package declaration using URLClassLoader java

I am trying to load class "SampleTest.class" from folder(C:\com\scheduler\jobs) in my current application, I could able to load class when it doesn't have package declaration.
The problem with when "SampleTest.class" has package declaration then I couldn't able to load and giving error No class found.
My current application when I am trying to load class :
**ReadInterfacesCount.java**
URL url = new URL("file:/C:/com/scheduler/jobs/");
ClassLoader cl = new URLClassLoader(new URL[]{url});
Class<?> aClass = cl.loadClass("SampleTest");
System.out.println("Interfaces count ==> "+aClass.getInterfaces().length);
SampleTest.class
package com.scheduler.jobs;
import java.io.IOException;
import java.io.Serializable;
import java.util.List;
public class SampleTest implements Serializable{
public static void main(String[] args) throws IOException{
System.out.println("From Sample Test");
}
}
When I run ReadInterfacesCount it is giving below error:
Exception in thread "main" java.lang.NoClassDefFoundError: SampleTest (wrong name: com/scheduler/jobs/SampleTest)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at com.test.ReadAllJavaClasses.getListeners(ReadAllJavaClasses.java:119)
at com.test.ReadAllJavaClasses.main(ReadAllJavaClasses.java:101)
When I remove package declaration in SampleTest file now I could able to load class.
Can anyone help me out?
Thanks,
Naresh Kallamadi.
As someone upvoted my comment, I'm converting that quick assumption to an answer
When Class.forName("SampleTest", ...) fails to instantiate a class named com.scheduler.jobs.SampleTest, but succeeds instantiating a class SampleTest, you might want to try Class.forName("com.scheduler.jobs.SampleTest", ...)
Edit: And as I wrote in the comment, it seems completely weird for me to digest code this way - I've never tried it. The next thing that comes to mind after your comment: When you want to load the class stored in C:/com/scheduler/jobs/SampleTest.class as com.scheduler.jobs.SampleTest, you might need to give C:/ as the path to the classloader, because that's the root of where it should search for a class of this package/name.
Coming back to the mentioned weirdness of the code: I don't trust any business level code that explicitly deals with classloading. Classloading is an infrastructure problem, and while you might solve the problem at hand, I believe that you're solving a completely wrong problem - you rather have severe problems with your underlying architecture (which can't be solved in this question)

Adding an annotation to a runtime generated class using Javassist

I'm using Javassist(Java 1.7) to add an annotation to the class ClassA, but i get the exception. What am i doing wrong? The code I tried looks like this:
ClassA.java
public class ClassA
{
}
add method
public static <T> Class<T> addXmlRootAnnotationDynamicly(Class<T> declaredTyp) throws NotFoundException, CannotCompileException, InstantiationException, IllegalAccessException
{
//pool creation
ClassPool pool = ClassPool.getDefault();
//extracting the class
CtClass cc = pool.getCtClass(declaredTyp.getCanonicalName());
// create the annotation
ClassFile ccFile = cc.getClassFile();
ConstPool constpool = ccFile.getConstPool();
AnnotationsAttribute attr = new AnnotationsAttribute(constpool, AnnotationsAttribute.visibleTag);
Annotation annot = new Annotation("javax.xml.bind.annotation.XmlRootElement", constpool);
attr.addAnnotation(annot);
// add the annotation to the class
cc.getClassFile().addAttribute(attr);
// transform the ctClass to java class
Class<T> dynamiqueBeanClass = cc.toClass();
//instanciating the updated class
// T sayHelloBean = dynamiqueBeanClass.newInstance();
return dynamiqueBeanClass;
}
call
Class<ClassA> addXmlRootAnnotationDynamicly = addXmlRootAnnotationDynamicly(ClassA.class);
Exception
javassist.CannotCompileException: by java.lang.LinkageError: loader (instance of sun/misc/Launcher$AppClassLoader): attempted duplicate class definition for name: "de/it_p/pvlight/share/util/ClassA"
at javassist.ClassPool.toClass(ClassPool.java:1099)
at javassist.ClassPool.toClass(ClassPool.java:1042)
at javassist.ClassPool.toClass(ClassPool.java:1000)
at javassist.CtClass.toClass(CtClass.java:1224)
at de.it_p.pvlight.share.util.JAXBUtil.addXmlRootAnnotationDynamicly(JAXBUtil.java:107)
at de.it_p.pvlight.share.util.JAXBUtilTest.addXmlRootAnnotationDynamicly(JAXBUtilTest.java:60)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.lang.reflect.Method.invoke(Method.java:606)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: java.lang.LinkageError: loader (instance of sun/misc/Launcher$AppClassLoader): attempted duplicate class definition for name: "de/it_p/pvlight/share/util/ClassA"
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
at java.lang.ClassLoader.defineClass(ClassLoader.java:643)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.lang.reflect.Method.invoke(Method.java:606)
at javassist.ClassPool.toClass2(ClassPool.java:1112)
at javassist.ClassPool.toClass(ClassPool.java:1093)
... 15 more
The root of your problem can be found in your stack trace:
attempted duplicate class definition for name: "de/it_p/pvlight/share/util/ClassA"
Your addXmlRootAnnotationDynamicly method takes a loaded class and redefines this very same class without changing its name. After this redefinition, you attempt to load the altered class one more time. This is however not possible in Java where any ClassLoader can only load a class of a given name one single time.
For this reason, the pool.getCtClass method takes a String instead of a loaded Class and works with CtClasses which are used to describe unloaded Classes. To overcome your problem, you have different choices:
Change the signature of your method to addXmlRootAnnotationDynamicly(String) and deliver de.it_p.pvlight.share.util.ClassA as the argument. Make sure that this class is not loaded before you transform it, anywhere in your code. You should therefore run the transformation at your application's startup to make sure that the class is not accidentally loaded before the transformation. Your altered Class is then loaded on cc.toClass().
Create a subclass of the argument class (or use interfaces) which uses a random name. The subclass is then type compatible to your argument class but is never loaded.
Use the Instrumentation API to redefine your loaded class at runtime.
Make sure that the input class and the output class are loaded with different ClassLoaders. (not recommended)

Issue with Java class loader

I compile a class successfully like this:
zookeeper#zookeeper-virtual-machine:~/zookeeper-3.4.5$ javac -cp "zookeeper-3.4.5.jar" org/zookeeper/Worker.java
But when I then try to run it Java's class loader can't find the class:
zookeeper#zookeeper-virtual-machine:~/zookeeper-3.4.5$ java -cp "zookeeper-3.4.5.jar" org.zookeeper.Worker
Exception in thread "main" java.lang.NoClassDefFoundError: org/zookeeper/Worker
Caused by: java.lang.ClassNotFoundException: org.zookeeper.Worker
at java.net.URLClassLoader$1.run(URLClassLoader.java:217)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
at java.lang.ClassLoader.loadClass(ClassLoader.java:321)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294)
at java.lang.ClassLoader.loadClass(ClassLoader.java:266)
Could not find the main class: org.zookeeper.Worker. Program will exit.
Here are the relevant parts of Worker.java
package org.zookeeper;
...
class Worker implements Watcher {
...
public static void main(String[] args) throws Exception {
Worker worker = new Worker(args[0], args[1],args[2]);
worker.processRequest();
}
Why can't the class loader load the class?
When the -cp flag is specified, the current directory is not automatically used in the classpath so needs to be added explicitly:
java -cp zookeeper-3.4.5.jar:. org.zookeeper.Worker
Why quote the jar anyway?
In any case, you still need your classes on the classpath, e.g.,
java -cp .:zookeeper-3.4.5.jar org.zookeeper.Worker

How to dynamically load a jar with common abstract Class?

I am trying to develop a plugin system, which provides a interface to load jar at runtime. Each jar contains a class that extends from a common abstract class. For example:
//BasicPlugin.java
package byv;
abstract class BasicPlugin {
abstract public int test(int a);
}
I implemented a subclass:
//PluginA.java
package byv;
import byv.BasicPlugin;
public class PluginA extends BasicPlugin {
#Override
public int test(int a) {
return a + a;
}
}
The subclass above was compiled and packaged into a jar file(PluginA.jar). This jar only contains PluginA.class. And then in the main project I load it using URLClassLoader:
private static void loadTest() throws Exception {
URL url = new File("PluginA.jar").toURI().toURL();
URLClassLoader ClassLoader = URLClassLoader.newInstance(new URL[] {url});
Class<?> clazz = Class.forName("byv.PluginA", true, ClassLoader);
BasicPlugin obj = (BasicPlugin) clazz.newInstance();
obj.test(2);
}
I have already added a reference to BasicPlugin in the main project. But errors still occured:
Exception in thread "main" java.lang.IllegalAccessError: class byv.PluginA cannot access its superclass byv.BasicPlugin
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:634)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:277)
at java.net.URLClassLoader.access$000(URLClassLoader.java:73)
at java.net.URLClassLoader$1.run(URLClassLoader.java:212)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
at java.lang.ClassLoader.loadClass(ClassLoader.java:321)
at java.net.FactoryURLClassLoader.loadClass(URLClassLoader.java:615)
at java.lang.ClassLoader.loadClass(ClassLoader.java:266)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at byv.Main.loadTest1(Main.java:18)
at byv.Main.main(Main.java:11)
So how can I fix this problem?
Since it is an IllegalAccessError I suggest you make BasicPlugin public to solve the problem. As far as I know the class you defined is package protected. As such it is not accessible from a different class loader. Since that is what you require for your plugin, it makes not sense to make the class anything else than public.
One more thing, URLClassLoader has a second constructor in which you can specify the parent loader. This loader is then used to load the plugin class. In a more complex environment you may want to specify that loader. Currently your code uses more or less the system loader, which is ok in your example, but I don't know what you intend to do later on. BasicPlugin.class.getClassLoader() gives you the right loader for that class for sure.
Pass the classloader context to use when constructing your URLClassLoader instance:
URLClassLoader ClassLoader = URLClassLoader.newInstance(new URL[] {url},
this.getClassLoader());

NoClassDefFoundError when running a class [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 11 years ago.
I am trying to run a class, but I get the following error:
java.lang.NoClassDefFoundError: MyClass
Caused by: java.lang.ClassNotFoundException: MyClass
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
Exception in thread "main"
It happens, although the main method is in MyClass and I run directly this class.
Why is this class not found, although I launch the program from it?
Here is some code:
public class MyClass extends A implements B{
public MyClass() throws Exception {
//make some initializations
}
public static void main(final String[] args) throws Exception {
MyClass myClass = new MyClass();
//do stuff with myClass
}
}
PS: I am using Eclipse Indigo.
EDIT
I have run the class in the Command Line twice:
D:\Eclipse JEE\Workspace2\Example\target\classes\com\example\main>java com.example.main.MyClass
Exception in thread "main" java.lang.NoClassDefFoundError: com/example/main/MyClass
Caused by: java.lang.ClassNotFoundException: com.example.main.MyClass
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
Could not find the main class: com.example.main.MyClass. Program will exit.
D:\Eclipse JEE\Workspace2\Example\target\classes\com\example\main>java GeoDAOImpl
Exception in thread "main" java.lang.NoClassDefFoundError: MyClass(wrong name: com/example/main/MyClass)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
Could not find the main class: MyClass. Program will exit.
You haven't really given us enough information to say for sure, but my guess is that either:
You're not giving the right fully-qualified class name
Your class isn't on the classpath
For an example of the first case, if your code looks like this:
package foo;
public class MyClass {
public static void main(String[] args) {
}
}
Then you should be running:
java foo.MyClass
EDIT: With the extra information provided, I suspect I know what's happened. I suspect the class was created not in a package, and a Run Configuration was created which just runs MyClass. It's now been moved into com.example.main, but without the Run Configuration being updated.
Go into the Run Configuration editor (click on the dropdown next to the "run" button, and select Run Configurations...) and find "MyClass", then check which class is going to be run, and edit it to put the right package name in.
You first need to compile your source file if you haven't already done so. Assuming that your class MyClass is not in a package, and you are in the directory that contains the source file MyClass.java, compile it with:
javac MyClass.java
You should now have a file named MyClass.class.
Then, to run it, you need to make sure that the directory that contains the MyClass.class file is in the classpath. If you do not have the CLASSPATH environment variable set, Java will by default look in the current directory, so you should be able to run it with:
java MyClass
If this doesn't work, you can explicitly put the current directory . in the classpath using the -cp option:
java -cp . MyClass

Categories