Wade Chandler has been a software engineer and consultant for 14 years. He has worked with many languages and technologies such C, C++, Java, C#, Perl, PHP, HTML, and JavaScript along with various server side specific technologies and various frameworks. Along with contributing to various open source projects, he is a member of the NetBeans Dream Team and former NetBeans Governance Board member. Wade has posted 5 posts at DZone. You can read more from them at their website. View Full User Profile

Java Module Systems, SwingWorker, Runnable, Thread and Class Loader Issues

02.18.2012
| 8992 views |
  • submit to reddit

People often have a hard time getting used to a Java module system's constraints on class loaders and dealing with compile time versus runtime dependencies. There are a lot of issues just around getting the dependencies organized.

Often overlooked is how threading impacts class loaders. NetBeans modules, when "they" create a thread for you, will generally set the context class loader to the current class loader. However, in your own code you need to handle this.

Note Runnable is mentioned above. This does not necessarily consider the cases of EventQueue.invokeLater and invokeAndWait as those things are generally cases where the object instances have been realized, and class loading is no longer in the picture, or at least they should be, as those things should be short and to the point as they happen on the EDT, but it focuses on Runnable when given to the Thread constructor.

However, this could become a source of issues, and if creating new object instances in the Runnable, and it is ever a possibility those classes could be included in more than one module in the targeted system, then you should probably go ahead and deal with a class loader change out as your code will be running on the EDT.

Either way, the reason this becomes important is class access and class collision.

Access deals with the visibility or permissions a given class loader gives the calling code. Calling code may not have access to a certain class, and thus the current class loader should not be the one to load classes, but should instead delegate that to another module which has access to not only the public API but the private API of the module itself. That would be the one loading the classes the caller can access or the public API of the called module.

Collision is a more subtle thing to deal with. Imagine one module has class mine.Foo and another module does as well. Even though these modules may not call or touch each other and thus not collide with each other under normal calling conditions, they may very well do that in a thread without setting the context class loader as those classes will have to be loaded some how, and here the system class loader will be used which will access all the class loaders, and that means either an arbitrary class must be chosen or the first one found, and in nearly all conditions this is not what you want.

In the NetBeans module system this will cause an error as the NetBeans developers do not want this to be a surprise and thus hide crashes. Others may load them; I'm not sure, so if anyone knows how various module systems handle this please comment. Either way, unless you give Java and the module system more guidance, you will run into strange and unusual problems.

Given a class, the following should really be used:

public class MyClass {

Runnable r = new Runnable(){
public void run(){
ClassLoader oldCl = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(MyClass.class.getClassLoader());
}finally{
Thread.currentThread().setContextClassLoader(oldCl);
}
}
};

Thread t = new Thread(){
public void run(){
ClassLoader oldCl = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(MyClass.class.getClassLoader());
}finally{
Thread.currentThread().setContextClassLoader(oldCl);
}
}
};

SwingWorker<Void, Void> = new SwingWorker<Void, Void>{
public Void doInBackGround(){
ClassLoader oldCl = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(MyClass.class.getClassLoader());
}finally{
Thread.currentThread().setContextClassLoader(oldCl);
}
return null;
}
};

}


This does a couple things at various runtimes. When the code runs in a regular Java application with no module system, the system class loader will always be used. Next, when run in a modular application, the current caller, or current module will use its class loader in the threaded logic. Finally, in both cases, the loader is reset to whatever it was before; for throw away threads, that is probably not a big deal, but what if your code is using a thread pool?

This is a basic convention to follow for safety and refactorability. Safety as noted in access and collision. If your code is used in a modular system, and does not follow the above, it will crash as soon as you add the same classes to other modules. Refactorability per the fact that if more than one module later adds a different version of a class, or the same version different class loader, then the application will start to crash until fixed, and if the person tracking down the issue has to spend time finding and/or fixing it, they can't focus on refactoring code to work with the same classes in different ways.

Another thing to keep in mind is there are times when you may need to pass a specific class other than your own for some block of code to pin-point an exact class loader. Imagine some code you are calling will need classes which your class loader does not have access as the module being called does not expose them as part of its public API.

So, there are times when you have to think beyond the current class loader, but the good thing is no matter which class works in the modular system, the code will continue to work if used outside of one in a standard Java application.

The one major time this differs are libraries written to load and use classes dynamically. MyBatis is a good example. In such cases, the current thread context class loader should be passed along. The idea being the caller is telling you which class loaders to use. This only applies to threads however as the module wrapping the called code will have configured the context class loader as needed for the current thread.

The MyBatis folks were working to address this issue the last time I was on the lists. Someone using it in such a context now should comment if able.

I hope this will help projects (open source and not) write Java code which is compatible in both modular and non-modular applications.
References
Published at DZone with permission of its author, Wade Chandler. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Mateo Gomez replied on Thu, 2012/05/24 - 1:42am

is this fixed now?

mexican dip recipes       
 

Matt Coleman replied on Fri, 2012/05/25 - 12:31am

this is awesome..hope it will be ok soon

 web designer buffalo

Rahul Dev replied on Mon, 2012/08/20 - 1:08pm

I’ve desired to post about something similar to this on one of my blogs and this has given me an idea. I’ve really found out a great deal studying this site. Plainly especially excellent content her www.newsletter-templates.biz

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.