Enhancing a java object at runtime - java

I am aware that using proxy capable libraries (javassist, JDK dynamic proxies, etc) that it is possible to enhance a class to implement an interface at runtime.
My question is: is it possible to enhance an instantiated object to implement an interface at runtime (and likewise provide appropriate method handlers).

No, we can't change a class that has already been loaded. And we can't replace a loaded class (within a classloader).
There may be a chance if you
load a class with a custom classloader
unload the classloader (should unload the class aswell)
load the modified class again with a new classloader instance
But that is very, very black magic...

Related

Is it possible for class loader to get classes already loaded by different class loader?

I have class Foo which needs class Bar as an import. Class Bar is loaded with different class loader than Foo and while defining Foo, class loader can't find Bar and throws ClassNotFoundException. Is it even possible to tell class loader, if class is not available in current class loader try looking in another?
Not generally, no. One could write such a classloader, but you can't 'edit' an existing classloader to work like this.
ClassLoaders are asked by either code itself (SomeClass.class.getResource will end up there, as will, of course, invoking findResource or loadClass or whatnot on an actual ClassLoader instance), or by the JVM (when a given class needs another to execute, the class's classloader is asked for it. This usually results in that CL returning it from cache, but if it hasn't been loaded yet by that CL, that would result in it being loaded).
The CL is then free to implement this request in any way it sees fit. URLClassLoader, which is also the default classloader (initialized with the classpath) will first ask its parent loader (in the default JVM config, that'll be the system loader that knows where e.g. java.lang.String lives, from the jmod files of your JDK installation), and return that result if available. It will then load by scanning classpath, and it ends there. You can't ask an existing URLClassLoader to change its behaviour, but you can of course write your own classloader - it's just code, you can extend the findClass etc methods.
Maybe elaborate a bit on what you're trying to accomplish. Why are multiple classloaders involved and what are you trying to accomplish by having multiple? (Say: Load classes from database BLOB fields, or, separate modules out, or, allow dynamic reloading of web handlers - that kind of answer).
Are you using an existing CL-based framework like OSGi, perhaps?

What classloader does "new" use, and how do i change it?

I'm developing a simple Plugin System and I basically want to control which classloader loads a class on a new instruction.
For instance I have a jar with my main program, and I distribute a class Foo.class in a extra packaged jar called Bar.jar.
I see three different possibilities to include the jar in my main program:
package Bar.jar with my main jar to include it in the classpath. This is obviously not feasible for a plugin system
Load the class Foo with an URL ClassLoader pointing to the jar. This would be too unfamiliar with the default java programmer to load classes manually via its name
Set a custom Classloader as the System-classloader via the -Djava.system.class.loader argument. But I dont really want to force the user to start his application with extra arguments.
Is there another way? Maybe something to register a Custom classloader for specific classes? or change the Classloader new uses at Runtime? Setting the ContextClassLoader of the Thread does not work.
When you load a class, the classes it refers to use the same class loader as it. This means to control the class loader used implicitly, you can to use a different class loader for the one which starts it all. e.g. Your first Runnable.
class A {
B b = new B();
The new B will chose the ClassLoader used for A (or a parent)
Setting the context class loader works for dynamic lookups like Class.forName(name); is the same as Class.forName(Thread.currentThread().getContextClassLoader(), name);
Once a class is loaded it will always use the same classes it depends on. It's not possible to swap different classes based on say a thread context. This means a class with a very specific classloader can use classes which are more generally used (e.g. as the general class is from a parent), however a more general used class cannot use a more specific class loader it is not aware of. i.e. ClassLoaders are not aware of their children.
One reason for this is that threads share memory. This means you can't say that when A creates a new B in one thread it will be different to another thread as the A instance could be accessed by either thread.

Understanding ClassLoaders in Java

I'm fairly new to the JVM and ClassLoaders. I have these two classes:
public abstract class CoreModule extends Entity
public final class EventManager extends CoreModule
At the start of the program, I create an instance of EventManager. So I understand that the JVM knows what Entity class is and how to load it (that is, it knows what ClassLoader to use), since EventManager is a grand-child. But when an Entity instance is passed by some serialization mechanism, it throws ClassNotFoundException. I have to manually set the ClassLoader to use (Event.class.getClassLoader()).
How come the JVM does not know what Event class is or how to load it if it already did it?
Actually the JVM does not figure this out "magically".
It is all based on a system class loader which will vary depending on the environment you use. Then each thread has a context ClassLoader which derives from this automatically.
The context ClassLoader you can change by using Thread.setContextClassLoader
If your serialization code should be able to resolve a class not visible from the context ClassLoader you need to set this the way you did.
Just by creating an instance of EventManager you didn't show the JVM how to load it. In fact, you're not talking to the JVM here. You're talking to one specific classloader, and when that same classloader is not in charge at the time of deserialization, you can get an error. That's why your problem is all about what clasloader is in charge at what point.

A custom system class loader is not used by all classes

I'm implementing a feature that requires passing dynamically generated types (in binary representation, serialised with Kryo) between several instances of JVM (over the network). In order to properly resolve what types are loaded and what are not I use a custom system class loader (passed as java -Djava.system.class.loader parameter), which is used by other dynamically created class loaders as a parent. This custom system class loader knows of its children and in case it cannot find a class these derived class loaders can be asked if they have it (this is a reverse to the standard hierarchical structure of class loaders).
These dynamically generated types get transferred and loaded between different JVMs perfectly fine. The problem arises when I try to deserialise an instance of some type (a corresponding class is loaded from disc and is identical for all JMVs) that references one of the dynamically generated types -- ClassNotFoundException is raised by an instance of Kryo, which tries to readClass by name of the dynamically generated type.
Inside method readClass there a call to Class.forName, which in turn does not use the specified custom class loader (that knows of all dynamically generated types) and instead uses sun.misc.Launcher$AppClassLoader instance.
Is it possible to specify a custom system-wide class loader, so that all classes are loaded with it in order to avoid the described problem?
Update
Further analysis revealed that ClassLoader.getSystemClassLoader() actually returns the specified custom system class loader. Fortunately, the Kryo library supports setting of a custom class loader specifically for loading classes upon deserialisation. These two facts formed the basis of a solution to the described problem.
How would you load the custom class loader if all classes have to laoded using that class loader?
One way to get around this is to create a native instrumentation agent. This is loaded before any classes are loaded.
Another way around it is to compile your own version of AppClassLoader and prefix it to the boot class path or add it to the libs/endorsed directory.

Dynamic class loading as one of the reason of permgen?

On different sites , Dynamic class loading is given as one of the reason of permgen problem.
As per my understanding , Dynamic class loading is loading the class as and when it is required.Alonwith that if Class A is loaded and it is referring another class B , it will also be loaded along with that. This is Dynamic class loading. Right? If yes, this is essential and inbuilt feature of JVM. What we can do about it?
Or my understanding is wrong here. when we say Dynamic class loading , are we reffering to custom class loaders here?
My last question related to above is, Class is loaded once by customer loader. So when we do hotdeployment on application server, how appserver loads the new version of class. Does it use different class loader here?
No, dynamic class loading refers to loading classes during runtime that are unknown at compile time, e.g., via Class.forName, or reflection (1, 2).

Categories