I am trying the following wrt Refleciton, let me know if this is possible
public class A {
void start(){
execute();
}
}
public class B extends A {
void execute()
{
doWork();
}
public abstract void doWork();
}
I have the above classes packaged in a jar and have it running on a JVM.
Now I am trying to create another class at run time, compile it at run time and trying to use reflection to invoke Class B's execute function().
public class C extends B {
#Override
public void doWork()
{
//Implementation
}
}
Reflection code:
Classloader = urls of application jars and url of C.class, compiled at run time. Parent loader - Thread.currentThread().getContextClassLoader()
I am also setting the current thread's context class loader to the classloader created above.
Class<? extends B> cls = (Class<? extends B>) Class.forName("className", true, clsLoader);
Object obj = cls.newInstance();
Method method = obj.getClass().getSuperclass().getMethod("start", new Class[0]);
method.invoke(obj, new Object[0]);
I am able to get the method and the invoke also gets called. However when class B's execute is called, it is trying to call the doWork() and then I run into an AbstractMethodError. Upon looking up on the exception, I see that the exception happens with incorrect classloaders/jars.
But I am not sure how do I go about fixing it in my case.
Can anyone assist?
First of all, let’s clarify the myths about the context class loader of a Thread: unless code asks explicitly for that loader via Thread.getContextClassLoader() (and uses it), it has no relevance for class loading at all.
Each class has an initiating class loader which defined the class and references to other classes within that class are always resolved via that initiating class loader. This even applies to reflective loading via Class.forName(String) (without an explicit ClassLoader); it will use the initiating class loader of the caller.
If you want to load C via a custom class loader which needs to have access to B, because C subclasses it, the best way to determine the parent loader for the creation of your new loader is B.class.getClassLoader(). However, in your simple setup, it’s the same loader as returned by ClassLoader.getSystemClassLoader() which is also the default class loader as returned by Thread.getContextClassLoader(), that’s why it worked.
You know that it worked because you could load C successfully. While other references might be resolved lazily, the direct superclass must be resolved immediately, so B is in scope of C’s loader.
Assuming that the absence of a declaration of execute() in A or an abstract modifier on class B are just oversights made by posting the question, the reason why invoking the method doesn’t work is much simpler: the method abstract void doWork(); is not public.
Since B and C are loaded by different class loaders, they are considered to reside in different packages, regardless of their qualified name. Therefore, the method doWork() in C does not override the method doWork() in B. This hasn’t been detected at compile-time, as, at compile-time, there is no class loader hierarchy. So the compiler considers B and C to reside in the same package, based on their qualified name (or explicit package declaration). Therefore the compiler assumes that C.doWork() implements B.doWork() and C can be declared non-abstract.
If you declare the method doWork() in B as public, it should work. And it should work much simpler:
try(URLClassLoader l = new URLClassLoader(new URL[]{/* url pointing to C */})) {
l.loadClass("C").asSubclass(B.class).newInstance().execute();
}
Related
I have a Spring bean (ChildBean extends Parent) which is extending an abstract class (Parent implements Runnable).
public abstract class Parent implements Runnable {
public final void run() {
// some code
}
public int overridenFunct() {
// some code
}
}
Child bean class variant which causes ClassCastException:
#Transactional
#Scope("prototype")
#Service("beanName")
public class ChildBean extends Parent {
#Override
public int overridenFunct() {
// some diff code
}
}
Everything works fine until I override public non-abstract method from parent class in child bean. After that a ClassCastException is thrown when I'm trying to create an instance of that bean.
Parent p = (Parent) appContext.getBean("beanName");
Bean object returned by getBean() is a ChildBean class instance (checked with debugger). Why does casting ChildBean object to its abstract parent class Parent not work?
So, without an overridenFunct() implemented in ChildBean everything works fine.
Could someone please tell what is the problem here?
UPDATE:
Changing method overridingFunct() to protected fixes the issue. But what if I need to override a public method? Is that allowed? I'm using Spring 3.2.8
UPDATE2:
Well, I didn't get to the point why overriding public method in abstract parent causes ClassCastException. As the resolution I did the following: created an interface with all public methods with common logic, an abstract class, which implements that interface and all "common" methods. Then all the child beans are extended from that abstract class, implementing its specific logic.
For anyone that may encounter this error, the following may prove to be useful in debugging this. First and foremost, the problem can be caused by the ClassLoader loading two copies of a particular class due to dependency overinclusion.
Supply the following option to your JVM via IDE or via
java -verbose:class {rest of your args / options}
Then, monitor the console output for the particular Parent class. A chance exists that the class has made it into the ClassLoader twice, perhaps by including a particular dependency more than once. Pay particular attention to the time when the bean is retrieved from lookup.
I was able to solve an issue on 4/22/2022 by using the above strategy to track down an issue in our Gradle build script that caused extra files to make their way into a WAR.
The Problem with your code is, that appContext.getBean("beanName") does not return an object that inherits from the class Parent.
A common mistake regarding classes with names like Parent is a wrong import.
Check if you are importing from the correct package.
If this does not fix the issue, make sure that appContext.getBean("beanName") returns the object you think it does.
It might return a Bean Object, that does not inherit from the Parent class.
The context also might not even contain your ChildBean object yet. Make sure it is added to it beforehand.
I write myOwnClassLoader through extends the classLoader and override its findClass method. And meet a interesting problem:
Here is the code segment:
public class MyClassLoader extends ClassLoader {
#Override
public Class<?> findClass(String name) {
byte[] bt = loadClassData(name);
return defineClass(name, bt, 0, bt.length);
}
private byte[] loadClassData(String className) {
...
}
public static void main(String[] args) throws ClassNotFoundException{
MyClassLoader myClassLoader = new MyClassLoader();
//Class<?> clazz = myClassLoader.findClass("com.classLoader.BMW");
Class<?> clazz = myClassLoader.loadClass("com.classLoader.BMW");
System.out.println(clazz.getClassLoader());//////////////////
}
}
when execute
Class<?> clazz = myClassLoader.findClass("com.classLoader.BMW");
the output meet my expectation:
output:
com.classLoader.MyClassLoader#xxxxxx
but when execute
Class<?> clazz = myClassLoader.loadClass("com.classLoader.BMW");
the output go beyond my mind:
output:
sun.misc.Launcher$AppClassLoader#xxxx
expect output
com.classLoader.MyClassLoader#xxxxxx
here is code segment of loadClass method in ClassLoader
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
.....
I debug it and find when we invoke loadClass at the first time the parent is sun.misc.Launcher$ExtClassLoader#6aa8ceb6 that is to say this reference is sun.misc.Launcher$AppClassLoader rather than com.classLoader.MyClassLoader#xxxxxx .
I search through internet and a blog define own classLoader tell that
it will set AppClassLoader as parent of MyClassLoader in default constructor.
I check it by
System.out.println(myClassLoader.getParent());
find the parent of MyClassLoader does be AppClassLoader how it achieve this, my default constructor do nothing and was this achieve in constructor method of its parent class ClassLoader? I read its parent constructor and still cant firgure out.
Anyway it seemd this cant explain why the this is AppClassLoader rather than MyClassLoader when we first invoke loadClass method.
And I guess it is because that *the classLoader of MyClassLoader is AppClassLoader but it is just a intuition I have no gist.
Everything will be appreciated.
Well, it’s all documented:
ClassLoader() constructor:
Creates a new class loader using the ClassLoader returned by the method getSystemClassLoader() as the parent class loader.
loadClass(String):
Loads the class with the specified binary name. … Invoking this method is equivalent to invoking loadClass(name, false).
loadClass(String,boolean-):
Loads the class with the specified binary name. The default implementation of this method searches for classes in the following order:
Invoke findLoadedClass(String) to check if the class has already been loaded.
Invoke the loadClass method on the parent class loader. If the parent is null the class loader built-in to the virtual machine is used, instead.
Invoke the findClass(String) method to find the class.
If the class was found using the above steps, and the resolve flag is true, this method will then invoke the resolveClass(Class) method on the resulting Class object.
Subclasses of ClassLoader are encouraged to override findClass(String), rather than this method.
This is also mentioned in the class documentation of ClassLoader:
The ClassLoader class uses a delegation model to search for classes and resources. Each instance of ClassLoader has an associated parent class loader. When requested to find a class or resource, a ClassLoader instance will delegate the search for the class or resource to its parent class loader before attempting to find the class or resource itself. The virtual machine's built-in class loader, called the "bootstrap class loader", does not itself have a parent but may serve as the parent of a ClassLoader instance.
This logic ensures clean scoping, i.e. classes of the parent scope don’t refer to classes of a sub scope, and that there are no conflicts between classes of the same qualified name, but defined by different class loaders. Such classes may still exist in distinct scopes, but not in nested scopes. But class loaders are not enforced to follow this rule. The delegation model was introduced with Java 2.
I know Java loads Classes in first Access (creating new Instance, calling static method or static field), but in this simple example I try to execute a jar file that uses some classes which there aren't in my ClassPath at run time. I expect (because of loading classes in first access) print my messages in static block and main method before an exception occurred. but I got "Exception in thread "main" java.lang.NoClassDefFoundError: com/example/DateAbstract" and nothing printed.
This occurred when I used an abstract class or interface in main class which that classes or interfaces are in another jar file.
public class Driver {
static { System.out.println("I am first.[static block]"); }
public static void main(String[] args) {
System.out.println("I am first.[ main method]");
DateAbstract date = new CustomDate();
System.out.println(date.sayDate());
}
in my another jar :
public class CustomDate extends DateAbstract {
#Override
public String sayDate() {
return new Date().toString();
}
public abstract class DateAbstract {
public abstract String sayDate();
}
when I use this code for add my classes to classpath at runtime. nothing changed. I got execption before execute static block.
public class Driver {
static {
System.out.println("I am first.[static block]");
try {
URL url = new File("lib/DateApi.jar").toURI().toURL();
URLClassLoader urlClassLoader = (URLClassLoader) URLClassLoader.getSystemClassLoader();
Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
method.setAccessible(true);
method.invoke(urlClassLoader,url);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
System.out.println("I am first.[ main method]");
DateAbstract date = new CustomDate();
System.out.println(date.sayDate());
}
}
Questions :
why is this happening and how to solve it ?
It’s not correct to say that in Java classes are loaded on their first access. You are confusing this with the initialization of a class, which implies executing the Java code of static initializer blocks and field initializers. The loading and verification might happen at an earlier time; the specification provides some freedom to the JVMs in this regard.
The key point here is that your main method instantiates an object of type CustomDate, stores it into a variable of the compile-time type DateAbstract and then tries to invoke sayDate() on that variable. This combination of instantiating CustomDate and invoking DateAbstract.sayDate() on it requires the verification of its correctness, i.e. whether CustomDate is a subtype DateAbstract. So the loading of these two classes will already happen at verification time.
You can easily check that this is the cause. If you change the type of the local variable date to CustomDate, the instantiated type and the receiver type of the method invocation are the same, so the correctness can be proven without loading the type, so it will be indeed deferred to the actual attempt to instantiate CustomDate, hence the messages will be printed.
Still, the loading time is an implementation-specific detail. A different JVM could load the referenced classes eagerly, even if they are not required for verification. The only safe way to ensure a deferred loading, is to use dynamic loading, e.g. Class.forName(String). Note that within the class detached this way, all types might be again referenced ordinarily. So if you do the dynamic loading once after the class path has been adjusted, there is not much impact on how you have to write the code nor its performance. Of course, having the code adjusting the class path and the code depending on it within the same class won’t work reliably.
I am little bit confused in class loading and initializing concept
1: Class.forName("test.Employee").newInstance();
2: ClassLoader.getSystemClassLoader().loadClass("test.Employee").newInstance();
3: new test.Employee();
Every line of above written code is creating an instance of Employee class but I don't understand what is the difference in all three methods.
The core differences between the three approaches come down to how the classes are located at runtime and what you can do with them.
For example...
Class.forName("test.Employee").newInstance();
Will use the current class's ClassLoader to search the class named Employee in the test package. This would allow you to discover classes that might not be available at compile time and which are loaded dynamically into the same class loader context. This will also search it's parent class loaders if the class is not found within the current context...
ClassLoader.getSystemClassLoader().loadClass("test.Employee").newInstance();
This will use the "system" ClassLoader, this typically the one that launched the main application.
Using either of these two methods is a great way to generate dynamic applications where the actual implementation of a Class is not known at compile type. The problem here is it can affect visibility and restrict what you can do with the loaded classes.
For example, while you may have loaded the test.Employee class and created an instance of it, unless you have a reference to test.Employee at compile time, you want be able to cast it. This is typically where interfaces come in very handy.
Equally, you could create your own ClassLoader instance and load classes or jars at runtime to provide, for example, plugins, factories or managers where the implementation is unknown at compile time. The functionality for these would, typically, be described through the use of interfaces.
Examples would include java.awt.Toolkit and JDBC java.sql.Driver
At the end of the day, the ClassLoader mechanism is providing a means by which a class file can be loaded and instantiated into the current JVM. The new keyword does a similar job, but the results are pre-determined at compile time
ClassLoaders are a very powerful feature and provide a lot of functionality, but can also be down right confusion, especially the way that they chain together
You might find...
The basics of Java class loaders
How ClassLoader Works in Java
of some help
You cannot create a instance of an Object unless class is loaded into the memory. In all three cases class is loaded and then instance is created.
class is loaded by Class.forName("test.Employee")
class is loaded by ClassLoader.getSystemClassLoader().loadClass("test.Employee")
class is loaded automatically as Employee class is referenced for 1st time.
Just to illustrate it with an example and complete the other answers:
public class ClassLoaderTest {
public ClassLoaderTest() throws InstantiationException, IllegalAccessException, ClassNotFoundException {
System.out.println("Current CL: "+getClass().getClassLoader());
System.out.println("Parent CL: "+getClass().getClassLoader().getParent());
// ClassTest class is defined in the current CL so I can dynamically create an instance
// from the current CL and assign it (forName uses the current CL)
ClassTest c1 = (ClassTest)Class.forName("ClassTest").newInstance();
System.out.println("CL using forName: "+c1.getClass().getClassLoader());
// the new keyword creates an instance using the current CL but doesn't have the
// advantages of creating instances dynamically
ClassTest c2 = (ClassTest) new ClassTest();
System.out.println("CL using new: "+c2.getClass().getClassLoader());
// Here we are indicating to use the system CL that in this case is the parent of the current CL
Object c3 = ClassLoader.getSystemClassLoader().loadClass("ClassTest").newInstance();
System.out.println("CL using system CL: "+c3.getClass().getClassLoader());
// This won't work because the ClassTest is defined in the current CL but I'm trying to assign it to a
// dynamically created instance of ClassTest associated to the system CL so:
// java.lang.ClassCastException: ClassTest cannot be cast to ClassTest
// ClassTest c4 = (ClassTest)ClassLoader.getSystemClassLoader().loadClass("ClassTest").newInstance();
}
public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
CustomClassLoader cl = new CustomClassLoader(Test.class.getClassLoader());
cl.loadClass("ClassLoaderTest").newInstance();
}
}
The output in my case is:
Current CL: CustomClassLoader#1cfb549
Parent CL: sun.misc.Launcher$AppClassLoader#8ed465
CL using forName: CustomClassLoader#1cfb549
CL using new: CustomClassLoader#1cfb549
CL using system CL: sun.misc.Launcher$AppClassLoader#8ed465
I'm using this custom ClassLoader (CL): www.javablogging.com/java-classloader-2-write-your-own-classloader/
i'm very confused...
I have a class which directly implements an interface:
public class Device implements AutocompleteResult
{...}
Here is proof that I'm looking at the right variables:
Object match = ...;
log.debug(match.getClass()); // Outputs 'Device'
log.debug(match.getClass().getInterfaces()[0]); // Outputs 'AutocompleteResult'
Yet when I try to cast an instance of the class to the interface:
AutocompleteResult result = (AutocompleteResult) match;
I get a ClassCastException!
ClassCastException: Device cannot be cast to AutocompleteResult
Also, isAssignableFrom returns false and i'm not sure why:
log.debug(AutocompleteResult.class.isAssignableFrom(Device.class));
from the doc:
Determines if the class or interface represented by this Class object is either the same as, or is a superclass or superinterface of, the class or interface represented by the specified Class parameter.
Shouldn't I always be able to cast a object to an interface its class implements?
Thanks.
This can happen if two different classloaders load a class named AutocompleteResult.
These two classes are then treated as entirely different classes, even if they have the same package and name (and even implementation/fields/methods).
A common cause for this is if you use some kind of plugin system and both your base classes and the plugin classes provide the same class.
To check for this issue print the value returned by Class.getClassLoader() on both offending classes (i.e. the class of the interface implemented by Device and the result of AutocompleteResult.class).
AKA when Java apparently doesn't Java.
I hit this problem recently with Play Framework 2.6.3, what helped me was this:
https://www.playframework.com/documentation/2.6.x/ThreadPools#Application-class-loader
I leave this info here for the people that might have the same problem.
To make it clearer, what helps is:
Injecting Application on an Eager Singleton and then using its classloader to load the classes I was having issues with.
To make it clearer
public class Module {
#Override
public void configure {
bind(TheClassLoaderLoader.class).asEagerSingleton()
public static class TheClassLoaderLoader {
#Inject
public TheClassLoaderLoader( Application application) {
ClassLoader classloader = application.classloader();
Class<?> interfaceClass = classloader.loadClass(InterfaceClass.class.getName());
classloader.loadClass(ImplementsInterfaceClass.class.getName()).asSubclass(interfaceClass);
The example here https://playframework.com/documentation/2.6.x/JavaDependencyInjection#Configurable-bindings
That uses Environment often throws a frustrating ClassNotFoundException
Cheers