I am creating a URLClassloader to load some jars. Each jar gets loaded correctly from a different classloader and each jar contains a class with a method run(). Now the body of this run() can create an anonymous inner class in it. However, because i created my URLClassloader in a try-with-resources block it gets autoclosed and at run time when it tries to load the anonymous inner class it throws a NoClassDefFoundError because the classloader is already closed.
Now my question is, what is the normal practice for these situations? is it ok to leave the classloader open so that when later it needs to load something else, it can? is there a way to reopen a closed classloader?
If I leave the classloader open, the compiler gives me warnings about potential resource leaks so I have a feeling this is like streams where you are not supposed to leave them open indefinitely. However because of the nature of classloaders, if it's not the same classloader that loads the anonymous class, it cannot be used in the outer class
here is the code where the classloader is created
public Player(File codePath) throws PlayerException {
try (URLClassLoader loader = new URLClassLoader(new URL[] { codePath.toURI().toURL() })) {
//load class from Jar where run() method creates anonymous class that comes in the jar too
} catch (ClassCastException | IOException | ClassNotFoundException | InstantiationException
| IllegalAccessException | IllegalArgumentException | InvocationTargetException
| SecurityException exc) {
throw new PlayerException("Error loading player's code", exc);
}
The life time of a class loader should be at least the life time of the instances of the classes loaded with it. As long as they and their classes are not eligible for garbage collection neither is their class loader. And should they need to load additional code or resources you need the class loader open.
So when you're done with a player, that's the time when you should close the class loader.
Rather than creating a new classloader for each player, you could use a Factory Pattern (or something similar):
URLClassLoader loader = PlayerClassLoaderFactory.getInstance().getClassLoader(codePath.toURI())
where the factory maintains the references to the classloaders (so the classes are not orphaned). Then you have the ability to "shutdown" the factory if needed to close the classloaders.
Related
I have a web application that have an upload functionnality which consist of uploading a package containing a java application (it may contains multiple dependencies)
For that , for every uploaded application, i'm creating a custom classloader to dynamically load the application classpath.
The solution is working fine until I get this error when uploading a new application:
javax.xml.stream.FactoryConfigurationError: Error creating stream factory: java.lang.ClassNotFoundException: de.odysseus.staxon.json.stream.impl.JsonStreamFactoryImpl
I have verified that my uploaded package contains staxon and also verifyed that my custom classloader can load that class:
Object a=Class.forName("de.odysseus.staxon.json.stream.impl.JsonStreamFactoryImpl",true , classLoader).newInstance();
So, why this exception and specially for this jar?
When you call Class.forName(className, initialize, classLoader) you are asking the JVM to load a class using that custom class loader. If you don't specify a ClassLoader -- for example just by calling Class.forName(className), then the JVM will use the ClassLoader known as the "context ClassLoader" for the thread. Each thread has one of these, and your code can change the context classloader somewhat easily.
If you have some code that causes a class to be loaded -- something like this:
MyClass foo = new MyClass();
The MyClass class will be loaded by the ClassLoader if it's not already loaded. It's not possible to call a constructor and supply a ClassLoader to load the class in case it's not already loaded. In this case, the thread's context ClassLoader is user.
Furthermore, if you call some code that you don't control, there are many ways in which that code could cause other classes to be loaded, and since you have no control over that code, the thread's context ClassLoader will also be used.
So, how do you set the thread's context ClassLoader? Easy:
ClassLoader cl = Thread.currentThread().getContextClassLoader();
ClassLoader myClassLoader = ...; // You figure this out
try
{
Thread.currentThread().setContextClassLoader(myClassLoader);
// Do work that requires your ClassLoader to work
}
finally
{
// Always restore the previous CCL after work is done
Thread.currentThread().setContextClassLoader(cl);
}
Another thing you'll want to do it make sure that your custom ClassLoader delegates any requests for class-loading to a parent ClassLoader. That parent ClassLoader should probably be the ClassLoader that would naturally be used if you weren't trying to use your own: the thread's context ClassLoader.
So, you probably want something like the following:
ClassLoader cl = Thread.currentThread().getContextClassLoader();
ClassLoader myClassLoader = new MyClassLoader(cl); // Try 'cl' before your custom class loading
try
{
Thread.currentThread().setContextClassLoader(myClassLoader);
// Do work that requires your ClassLoader to work
}
finally
{
// Always restore the previous CCL after work is done
Thread.currentThread().setContextClassLoader(cl);
}
You can find more information about ClassLoaders, and, specifically the TCCL, in these few references:
http://docs.oracle.com/javase/jndi/tutorial/beyond/misc/classloader.html
Difference between thread's context class loader and normal classloader
http://www.javaworld.com/article/2077344/core-java/find-a-way-out-of-the-classloader-maze.html (also referenced from the previous reference)
http://njbartlett.name/2012/10/23/dreaded-thread-context-classloader.html
My purpose is to dynamically inject new attributes + getter setter methods to a class definition at runtime. Currently I have a method to regenerate the code with newly added attributes which then will compile the generated code.
Initially I'll have a template for each class at compile time. Upon running the project, the template class is loaded to runtime. I have written some code to dynamically generate java code and compile it. When I load the newly created class using the below code, I am not able to access injected methods. I think I am not able to overwrite existing runtime definition. I went through a lot of blogs but still couldn't understand why. Please help.
I am accessing the newly added methods in DROOLS and its not referenced in any other class which can raise issues during compilation. Rules of the rule engine with new attributes are updated at runtime and so I need to adapt my code accordingly. Below is the ClassLoader code. This code doesn't throw any exception but fails to solve my purpose. Not sure if coding is right.
public static boolean loadClass2RunTime() {
try {
File folder = new File("target");
File dir = new File(folder, "com/itap/template");
File[] classFiles = dir.listFiles();
URL[] url = new URL[] { folder.toURI().toURL() };
int i = 0;
for (File classFile : classFiles) {
if (classFile.getName().matches(".*\\.class")) {
System.out.println(classFile.getName().substring(0,
classFile.getName().lastIndexOf(".")));
ClassLoader loader = URLClassLoader
.newInstance(new URL[] { folder.toURI().toURL() });
Class cls = loader.loadClass("com.itap.template."
+ classFile.getName().substring(0,
classFile.getName().lastIndexOf(".")));
ClassLoader temp = cls.getClassLoader();
}
}
return true;
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return false;
}
URLClassLoader can be useful when you need to load newly generated classes at runtime. Unfortunately, you will not be able to reload the definition of a already loaded class (i.e. reload a class) using URLCLassLoader.
When I load the newly created class using the below code, I am not
able to access injected methods. I think I am not able to overwrite
existing runtime definition.
URLClassLoader will check if the specified class has been already loaded. If found it simply returns the instance pointing to loaded class. Thus you will not be able to overwrite existing runtime definition.
Solution:
A standard approach to support dynamic class reloading in Java, one should read the byte information of the class (from its .class file) and write a custom class loader to load a class using this byte information.
Points to remember while using custom ClassLoader:
To reload a class, existing instance of the ClassLoader (which loaded the class) and all the loaded instances of the class should be garbage collected.
Custom ClassLoader must have load only specific classes (which needs to be loaded / reloaded). Request to load all the other classes (in-build Java classes or classes from other packages) must be delegated to its parent class loader. Trying to load in-built system classes might result in privilege exception.
The steps followed by the class loader when loading classes are:
Check if the class was already loaded.
If not loaded, ask parent class loader to load the class.
If parent class loader cannot load class, attempt to load it in this class loader.
When you implement a class loader that is capable of reloading classes you will need to deviate a bit from this sequence. The class reloading request should not be delegated to the parent class loader.
Here are sample link which can help you develop your custom class loader in Java.
http://www.javablogging.com/java-classloader-2-write-your-own-classloader/
http://tutorials.jenkov.com/java-reflection/dynamic-class-loading-reloading.html
Edited after your comment:
I think the statement InputStream stream =
getClass().getClassLoader().getResourceAsStream(name); of
loadClassData function in the example is not picking up the latest
version of the class.
You are right, it is not picking up the latest version of the class simply because it is using existing ClassLoader to get the stream (which points to the old version of your class).
You can rather use,
FileInputStream stream = new FileInputStream("Path to your class file");
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int data = stream.read();
while(data != -1){
buffer.write(data);
data = stream.read();
}
stream.close();
byte[] classData = buffer.toByteArray();
to read the byte information for the class and try to load it using your version of ClassLoader (custom ClassLoader).
I have a case where I need to create a lot of class loaders in my application to temporarily make some code visible while user supplied scripts are running. I'm using an URLClassLoader for this and it works pretty well.
When the script terminates, I want to "unload" or "close" the class loader to free the resources.
Is it enough to set the reference to the class loader to null? I'm especially wondering if I'll eventually run out of file handles because the extra classes are in JAR files.
PS: Must work with Java 5 and up. Yeah, I know...
A little late, but hopefully this'll be helpful for those who come to this Question later (like me).
With Java 7, a close() method has been added to URLClassLoader, which is exactly what OP was asking for.
EDIT (thanks to #Hot Licks): OK, so it isn't exactly what the OP has asked for. It doesn't free up all the resources, or make the resources and the loader collectible. It simply prevents the loading of more resources using the class loader. It does, however, close the jar file that was loaded with the URLClassLoader.
If you can't use Java7 and it's close() method, use reflection to close all open JAR archives of a classloader, like so:
public void close() {
try {
Class clazz = java.net.URLClassLoader.class;
java.lang.reflect.Field ucp = clazz.getDeclaredField("ucp");
ucp.setAccessible(true);
Object sun_misc_URLClassPath = ucp.get(this);
java.lang.reflect.Field loaders =
sun_misc_URLClassPath.getClass().getDeclaredField("loaders");
loaders.setAccessible(true);
Object java_util_Collection = loaders.get(sun_misc_URLClassPath);
for (Object sun_misc_URLClassPath_JarLoader :
((java.util.Collection) java_util_Collection).toArray()) {
try {
java.lang.reflect.Field loader =
sun_misc_URLClassPath_JarLoader.getClass().getDeclaredField("jar");
loader.setAccessible(true);
Object java_util_jar_JarFile =
loader.get(sun_misc_URLClassPath_JarLoader);
((java.util.jar.JarFile) java_util_jar_JarFile).close();
} catch (Throwable t) {
// if we got this far, this is probably not a JAR loader so skip it
}
}
} catch (Throwable t) {
// probably not a SUN VM
}
return;
}
When all classes that the class loader loaded no longer have any references, and all references to the class loader itself have been erased, the class loader and the classes it loaded will be garbage collected as a group.
Note that this is dependent on having the JVM attribute set that causes unreferenced classes to be unloaded. It's set by default in most environments, but may not be in some embedded cases.
[Note that it's a non-trivial matter to remove references to a class. Any other class that references it by name will of course prevent removal. So the class must be loaded using ClassLoader.findClass or something similar.]
If you do not longer have classes (and object) loaded from that classloader, and if you do not keep any reference to that classloader, it will automatically handled by the garbage collector.
There are no close() methods in URL class loader or any of its parent classes, so you're out of luck.
Shouldn't GC handle this?
I extended URLClassLoader and made a close method based on Java 7s. I wanted to develop my IRC bot on my iPad 2, so I did what was needed. Now my plugin system is stable on Java 6 and 7, hurray.
I am writing a static analysis tool for an assignment, it analyses Java bytecode using the ASM library. One of the parts of ASM that we use requires (or at least, appears to require) that the class be loaded from the ClassLoader.
We were hoping the tool would be able to analyse .class files without requiring them on the classpath. We already load the .classes from a specified directory at run time and read them in using an InputStream. This is acceptable for ASM in most cases. There are some classes, such as SimpleVerifier, which attempt to load the classes though.
Is it possible, under this scenario, to register the .class files to be loaded so that calls to Class.forName() will load them? Or is there an easy way to extend the ClassLoader to allow this?
Edit: the information on URLClassLoader was useful. Unfortunately, using Thread.currentThread().setContextClassLoader() to an instance of that didn't work in this scenario. The library code I'm calling into uses a loader it retrieves on instance initialisation using getClass().getClassLoader().
By the time I set the URLClassLoader the class hasn't been initialised so I guess the contextClassLoader does not load that class.
Have I understand the responses correctly? Would using the URLClassLoader to load the 3rd party class be a possibility?
Almost.
If you have classes compiled somewhere, you can load them with a URLClassLoader. You can then set this ClassLoader to be the ClassLoader for the current Thread: Thread.setContextClassLoader(ClassLoader)
Users can that get the current threads context class loader and use that to access the class definition.
First of all, ASM can be used in a such way that it won't use ClassLoader to obtain information about classes.
There are several places in ASM framework where it loads classes by default but all those places can be overridden in your own subclasses. Out of the top of my head:
ClassWriter.getCommonSuperClass() method is called only when ClassWriter.COMPUTE_FRAMES flag is used and can be overwriten to not use ClassLoader to get inforamtion about classes. You can find an example of that in ClassWriterComputeFramesTest that introduces a ClassInfo abstraction
Similarly SimpleVerifier.getClass() method is used by SimpleVerifier.isAssignableFrom() and you can overwrite the latter and use the ClassInfo abstraction to find the common super type. If I am not mistaken, AspectWerkz project had implemented similar thing in its type pattern matching code. Also note that there is SimpleVerifier.setClassLoader() method, which you can use if you still want to load your own classes.
On a side note, on a Sun's JVMs, loaded classes gets to PermGen area and can't be unloaded, so it is not a good idea to load classes only for static code analysis purposes if you can avoid that, especially if tool would be integrated into a long-live process, such as IDE.
You can't, as far as I know, extend the System class loader at runtime, but you can dynamically load classes from an arbitrary location (jar or directory) using URLClassLoader.
You could try to setup a "launcher" in the startup of your application that creates an URLClassLoader passing it the locations on the classpath and your own .class locations and start the application from that classloader.
When the SimpleVerifier is loaded by the URLClassLoader it will also be able to load the classes from the extra locations.
Yes, you can use URLClassLoader
I have a test where I do load the class at runtime. This class is not in the classpath (nor even exist when the test is run for that matter ), later is it loaded and works great.
Here's the code.
void testHello() throws MalformedURLException, ClassNotFoundException {
URL[] url = {
new URL("file:/home/oreyes/testwork/")
};
try {
new URLClassLoader(url).loadClass("Hello");
throw new AssertionError("Should've thrown ClassNotFoundException");
} catch ( ClassNotFoundException cnfe ){}
c.process();// create the .class file
new URLClassLoader(url).loadClass("Hello");
// it works!!
}
Taken from this question.
I created my own ClassLoader its quite simple.
/**
* Used to hold the bytecode for the class to be loaded.
*/
private final static ThreadLocal<byte[]> BYTE_CODE = new ThreadLocal<byte[]>();
#Override
protected Class<?> findClass(final String name) throws ClassNotFoundException {
final byte[] bytes = BYTE_CODE.get();
if (null == bytes) {
throw new ClassNotFoundException(name);
}
return this.defineClass(null, bytes, 0, bytes.length);
}
From the perspective of a cross application/applet java accessibility service, how would you link to a package but only optionally execute an action based on existence/availability of a package (being already loaded) at runtime?
I think what I'm interested in here is a way to resolve the class identity crisis but rather than the issue being between 2 apps sharing objects, being a service loaded at a higher level of the class loaders.
It seems like reflection is the way to go, but I am not sure how or if I can implement a derived class this way. I need to add a specific listener derived from the specific optional classes, I can load the listener using the applet class loader but the internals still fail. Say you wanted to add an JInternalFrameListener, but Swing wasn't guaranteed to be available, using reflection you can find the method to add the listener, but how can you create and have the frame listener work if it cannot find any of the related classes because they can't be found in the base classloader! Do I need to create a thread and use setContextClassLoader to the classloader that knows about swing so that I can get the class to be loaded reliably? simply trying to set the class loader on my existing thread didn't seem to work.
Earlier description of issues
Sorry, I'm not quite sure what to ask or how to make this clear, so it rambles on a bit.
Say a class uses some feature of another, but the other class may not always be available - say finding the website from JNLP if this is a JNLP app.
At one stage I thought that simply compiling against JNLP would mean that my class would not load unless JNLP was available, and so to identify this optional section I simply wrapped a try{} catch( NoClassDefFoundError ) around it.
Later something changed (perhaps changing jdk or ?? I don't recall) and it seemed that I should also use a try{} catch( ClassNotFoundException ).
Now I wanted to extend this idea to other optional features, but it doesn't seem to work consistently.
Say I wanted to add some feature to do something more advanced in a JRE1.6 runtime using the same jar and classes as I run in a JRE1.3, or say I want to handle some controls in a specific gui toolkit which may not always be used like SWT or oracle.forms.
Is there some way of doing this more reliably? It just seems wrong to cause an exception and catch it to ignore it all the time.
The current issue comes down to being able to compile against oracle.forms but then the accessibility component installed in ext is unable to access the oracle.forms classes even though objects from the oracle.forms package have been created. If I throw the frmall.jar into the ext directory to test then the accessibility component works up to the point that the whole lot gets flakey because of the different versions of the same package.
I seem to be caught up on an issue with the class loader not being the right one or something (??). How do I find the right one?
Edit:
The answers so far are kindof interesting but not quite getting me where I want to be.
In the case of the gui components I currently compile in the form of a factory something like...
import oracle.forms.ui.*;
import java.awt.*;
static public IComponentNode newNode( INode parent, Component component ) {
System.out.println( component.getClass().toString() );
try{
if( component instanceof FormDesktopContainer )
... does stuff here like return new FormDesktopNode( parent, (FormDesktopContainer) component )
} catch ( NoClassDefFoundError a ) {
System.out.println( a.getMessage() );
}
where it prints out class oracle.forms.ui.FormDesktopContainer and then throws and exception on the instanceof call with NoClassDefFound thus printing out oracle/forms/ui/FormDesktopContainer
So how can it have an instance of a class yet not be able to find it?
How about this? messy, but it ought to work:
public boolean exists(String className){
try {
Class.forName(className);
return true;
}
catch (ClassNotFoundException){
return false;
}
}
You can check the availability of a class by calling
ClassLoader.getSystemClassLoader().loadClass("my.package.MyClass")
if it throws a ClassNotFoundException, it's not available. If you get the Class object, it is. You can then choose behaviour based on whether or not the class is available.
I suggest compiling the majority of your code against your minimum target. Have code that uses particular optional libraries clearly separated, but dependent upon the bulk of your code. Dynamically load the code that uses optional libraries once. The main class should do something that checks for the presence of the required library/version in its static initialiser.
In the case of JNLP, your JNLP main class load the JNLP dependent code statically.
(Note that attempting to catch class loading related exceptions from normally linked code is unreliable.)
getSystemClass loader was not useful for this purpose as there where multiple possible class loaders to interact with based on which applet the given window was in. The accessibility components being loaded at a more base class loader cannot see the applet specific classes.
To interact with the objects reflection does the job, though it does add so much more to maintain.
// statically linking would be
return component.getText();
// dynamically is
try {
return (String)component.getClass().getMethod("getText", new Class [] {}).invoke(component, new Object [] {});
} catch (Throwable e) {
e.printStackTrace();
}
The trickier bit is in writing a class derived from an interface that is not directly accessible, using the Proxy service allows this to be accomplished, providing the proxy service the applet specific class loader and the dynamically loaded class for the interface.
public void addListener(Container parent) {
if (parent == null) { return; }
if ("oracle.forms".equals(parent.getClass().getName())) {
// Using the class loader of the provided object in the applet
// get the "class" of the interface you want to implement
Class desktopListenerClass = Class.forName( "oracle.DesktopListener"
, true, parent.getClass().getClassLoader());
// Ask the proxy to create an instance of the class,
// providing your implementation through the InvocationHandler::invoke
Object desktopListener = Proxy.newProxyInstance(
parent.getClass().getClassLoader()
, new Class[] { desktopListenerClass }, new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if ("functionName".equals(method.getName())) {
// do stuff
}
return null;
}
});
// do something with your new object
Method addDesktopListener = parent.getClass().getMethod("");
addDesktopListener.invoke(parent, desktopListener);
}
}
examples cut down to show general method