views:

232

answers:

6

Consider a scenario that a java program imports the classes from jar files. If the same class resides in two or more jar files there could be a problem.

  1. In such scenarios what is the class that imported by the program? Is it the class with the older timestamp??

  2. What are the practices we can follow to avoid such complications.

Edit : This is an example. I have 2 jar files my1.jar and my2.jar. Both the files contain com.mycompany.CrazyWriter

+1  A: 

By default, classes are loaded by the ClassLoader using the classpath which is searched in order.

If you have two implementations of the same class, the one the class loader finds first will be loaded.

If the classes are not actually the same class (same names but different methods), you'll get an exception when you try to use it.

You can load two classes with the same names in a single VM by using multiple class loaders. The OSGI framework can manage lots of the complexitites for you, making sure the correct version is loaded, etc.

Robert Christie
A: 

First, I assume that you mean that the same class resides in two more jar files...

Now, answering your questions:

  1. Which class is imported is dependent on your classloader and JVM. You cannot guarantee which class it will be, but in the normal classloader it will be the class from the first jar file on your classpath.
  2. Don't put the same class into multiple jar files, or if you are trying to override system classes, use -bootclasspath.

Edit: To address one of the comments on this answer. I originally thought that sealing the jar would make a difference, since in theory it should not load two classes from the same package from different jar files. However, after some experimentation, I see that this assumption does not hold true, at least with the default security provider.

Paul Wagland
1. What about the **default** classloader (which is what the question is about)? 2. There are valid use cases for putting different versions of a same class in multiple JARs (e.g. to patch a class).
Pascal Thivent
@Pascal You might think that this is a valid usecase, but it is much better to replace the original jar, since in general you need to restart anyway. The answer is, as above, the classloader will use whichever class it finds first. In general, that will be from the first jar file on the classpath.
Paul Wagland
@Paul BEA **won't** give you new weblogic.jar so no, it's not better to replace the original jar (the problem is not to restart or not). And all JVMs I've worked with will **always** pick up the first class found.
Pascal Thivent
@Pascal I have updated the answer, since I thought that sealing the jar would have an affect, but it did not. I still don't think it is a good idea to have the same package split across multiple jar files, but I will concede there are times when it could be useful, even if it would negate any support contracts you have with the vendor ;-)
Paul Wagland
Regarding your edit: the JVM will throw an exception when attempting to load *different* classes in the same package from JARs with different credentials. Having the *same* class in different JARs is not the same scenario.
Michael Borgwardt
@Michael I just did the test, and I wasn't even getting that exception.... which is why I assumed that it was part of the security provider configuration.
Paul Wagland
A: 

The ClassLoader is responsible for loading the Classes. It scanns the ClassPath and loads the class that it found first. If you have the same Jar twice on the ClassPath or if you have two Jars that contain two different versions of the same Class (that is com.packagename.Classname), the one that is found first is loaded.

Try to avoid having the same jar on the classpath twice.

phisch
A: 
  1. Not sure what you meant by "the same class resides in two more classes"

    if you meant inner/nested classes, there should be no problem since they are in different namespaces.
    If you meant in two more JARs, as already answered, the order in the classpath is used.

  2. How to avoid?
    A package should be in only one JAR to avoid duplicated classes. If two classes have the same simple name, like java.util.Date and java.sql.Date, but are in different packages, they actually are different classes. You must use the fully qualified name, at aleast from one of the classes, to distinguish them.

Carlos Heuberger
A: 

If you have a problem finding out which version of a class is being used, then jwhich might be of use: http://www.fullspan.com/proj/jwhich/index.html

James B
A: 

If the same class resides in two more jars there should be a problem.

What do you mean exactly? Why should this be a problem?

In such scenarios what is the class that imported by the program? (Class with older timestamp??)

If a class exists in two JARs, the class will be loaded from the first JAR on the class path where it is found. Quoting Setting the class path (the quoted part applies to archive files too):

The order in which you specify multiple class path entries is important. The Java interpreter will look for classes in the directories in the order they appear in the class path variable. In the example above, the Java interpreter will first look for a needed class in the directory C:\java\MyClasses. Only if it doesn't find a class with the proper name in that directory will the interpreter look in the C:\java\OtherClasses directory.

In other words, if a specific order is required then just enumerate the JAR files explicitly in the class path. This is something commonly used by application server vendors: to patch specific class(es) of a product, you put a JAR (e.g. CR1234.jar) containing patched class(es) on the class path before the main JAR (say weblogic.jar).

What are the practices we can follow to avoid such complications.

Well, the obvious answer is don't do it (or only on purpose like in the sample given above).

Pascal Thivent