Will using multiple version of a jar in an application cause problems? - java

I came across an application in which multiple versions of jar files are included. For instance commons-fileupload-1.8.jar and commons-fileupload-1.6.jar.
Would this cause any issues?
Thanks,
Raghuram

Yes, that's a bad idea. What will probably happen if you're lucky is that whichever of the two versions that comes first in the classpath will satisfy all the references. If that happens, then the other versions of the .jar file won't matter at all. However, old code that relies on an old version of the library might incorrectly pick up new versions of some classes, and so all sorts of weird bad things can happen.
Now, in an application with many separate class loaders, such a thing might work out, as long as the separate subsystems with separate class loaders keep the different versions separated. If you're talking about multiple references to a .jar in the system classpath, however, then it's not a case of multiple class loaders.

In my experience, yes it will. The jar that gets used will be the one that is loaded first and that is based on the class loader and not, I think, in a guaranteed order. So that means that some code might be depending on a feature in version 1.8 and then 1.6 gets loaded and throws an exception when you try to use it.

There will only be issues if both versions are actually loaded through the same class loader, e.g. by both appearing on the regular classpath.
It can be made to work if you load the different versions through separate class loaders.
Presumably the application you looked at is doing this. Or they just upgraded the JAR and forgot to delete the old version.

Definitely and it might give you different results sometimes depending on the app server and sometimes depending on the packaging.
If your application uses a class say X which is in both jars, the X.class one of them will be loaded by the classloader, and lets say that needs a class Y which is in both jars again one of them will be loaded (usually the first) but there is no guarantee that they will be from same jar.
So if there are two versions of same jar you need to inspect why this is happening and try and remove one of them. (If you are using maven there are different ways of achieving this)

yes it causes problems because only one of them will actually be used depending on which one gets loaded by the class loader(s) and what order they are loaded.

Related

What I have to do to guarantee that ccc.jar is loaded before aaa.jar?

Does somebody know in which order of precedence are the jars loaded?
Having several jars in WEB-INF/lib (in a war inside an ear in WAS 6.1).
Let's say aaa.jar, bbb.jar, ccc.jar. I have two different versions of a class paq1.paq2.paq3.MyClass inside aaa.jar and ccc.jar
The one inside ccc.jar is the correct one; the one in the aaa.jar is the wrong.
It seems that the wrong version is localized before the correct one.
Does somebody know what I have to do to guarantee that ccc.jar is loaded before aaa.jar?
(This is a simplification of a more real/complex problem, so renaming jars doesn't apply in this case).
Thank you in advance
I don't believe the servlet specification guarantees any specific Classpath ordering for the jars in the lib-folder. Hence you are looking at vendor specific functionality or - even worse - vendor specific accidental behavior, which tends to be very brittle.
If the bad class is in your deployment, the cure is removing the bad class definitions from your deployment. I would suggest that your build procedure is responsible for this.
If the bad class is in WAS itself you can usually override it by putting jars in an extension folder in the server itself, not as part of your deployment.
JVM takes class from the first jar in class path, where appropriate class exists. All others are discarded. You can remove this jars from WEB-INF and put them directly to webserver's class path. But this will be ugly solution.
WebSphere Application Server makes no guarantees about the ordering of JARs within WEB-INF/lib, and there is no option to force a particular ordering. I recommend removing duplicate classes and resources.

Loading two classes in different JARs

I got two classes with the same package in different JARs. Until the previous version, both classes were identical, so i had no issues in loading them. Now, one of them has a new method added and if I want to access it, not only should I import the class with that package, i also need to make sure the jar with the correct class comes first in the classpath.
i.e. javac -classpath "%classpath%;a.jar;b.jar" MyClasses..
where a.jar has the class with my new method.
Now, how do i ensure this when my app goes to production, where it's deployed as an EAR file, with all the libraries under WEB-INF/lib?
How do I know which jar gets the preference over the other? Is it the alphabetical order like a.jar is given the first preference over b.jar?
I've read this safe-class-imports-from-jar-files thread and got to know about writing a custom classloader, but is there a better simpler solution that? Cos I'm just going to access this method in that whole JAR in this current project and writing a classloader seems a bit overkill.
And please don't ask me "Why the hell same class with same package in different JARs?" It's absolutely out of my control and it'll take some time to get this corrected.
Environment details: IBM WAS 6.1 on their 1.5 Java.
Please ask me more questions, if I don't make much sense. Thanks in advance!
You can try to change the startup script of your server and specify the jar with the correct class in the bootclasspath by using java -Xbootclasspath .... Otherwise there is no guarantee which one of the 2 jars will load up first.
As far as I know, the order of jars being loaded from WEB-INF/lib is arbitrary - I asked a similar question about JBOSS and got the reply ( from RedHat ) that it depends on the order that java.io.File.listFiles() returns them in ( and that is not a guaranteed order ).
A custom classloader would be an option, but have you considered repackaging the jars - removing the duplicated classes?
Websphere allows you to specify the order in which classloaders of a particular application are inquired when searching for a class (the classloaders are hierarchically structured, from the topmost that loads JRE classes, down to classloader loading classes in your WAR).
During deployment of an app, you can specify if the order of inquiring the classloaders when searching for a class. There are two modes - Parent first (i.e. query the topmost classloader first) and parent last (query the app classloader first). This can be specified on both EAR and WAR level.
Packaging the duplicated jars to different locations in the app (e.g. one to EAR's classpath, the other to WAR's WEB-INF/lib) and setting the classloader orderING apropriately may solve your problem. However, if both your JARs have to be on the same level (e.g. WEB-INF/lib), then there's no way to specify which one will be used when loading the duplicated class.
The order of the JARs in one application is likely to be alphabetical but the order of applications might not. Additionally, it depends on how the server handles classloading, i.e. whether it replaces existing classes or skips the new ones.
Although you already stated that, I'd still like to give that advice: Having the same class in multiple JARs deployed in one application (which could happen with versioned jars, for example) is always a bad idea. Your better off to invest the time to fix that instead of trying to mess with class loading.
This might come out to be pretty vague but I do remember resolving this issue a long time back by messing around with the WAS admin console for that given application and rearranging the relevant JAR files using their web UI. Not sure if this is an acceptable step in your case but worth a try in case everything else fails.
assuming you have some control over the deployment, fix the classloading yourself. combine the problematic jars yourself by unzipping them in reverse loading order into the same directory and then re-zipping into a new jar. then deploy the app with the new combo jar. no duplicate classes, problem solved.
or, just delete the dupe classes from the jars before deploying.

select different jar at runtime - toggling

I was wondering if there was a way to select different versions of the same jar at runtime. I am hoping to avoid using maven profiles since this would be a build-time selection.
Lets say there are two versions of the same jar:
greatFeature_version_A.jar
greatFeature_version_B.jar
My initial idea was to use JMX to create a basic runtime toggle selecting between those two jars which are both included in the classpath. Also, the contents of the two jars are the same (no versioning or different naming of the internal classes).
So when a class is requested, lets say from version_A, the class loader will always select the first one it finds, regardless of which jar it belongs to.
My thinking is that no effective runtime toggling can be achieved this way. I was wondering if anyone might have a experienced something similar and have a recommended workaround. I am also hoping to avoid writing a custom class loader if possible.
Many thanks!
P.S. Other related questions on SO indicate custom class loaders, like this one.
You can use jarjar to "rename" the packages so greatFeature_version_A.jar's packages start ajar.* and the other start bjar.* This way you can use the code from both jars in the same application, potentially at the same time.

Resolving java package dependencies

It is time to sub-divide a platform I'm developing and I'm looking for advice on how to handle cross-component dependencies. I spose there a many cases, so I'll give an example.
I have an Address class that I want to make visible to developers. It is also referenced by classes in my.Contacts, my.Appointments, and my.Location packages - each of which I want to be separately compiled, jar-d, and delivered. Of course I want Address to be a single class - an Address works across these platform components transparently.
How should Address be packaged, built, and delivered?
Thanks!
Two thoughts:
Address sounds like a common component that can be used in different deliverables and so should be available in some common or core library
It may make sense for your components to talk to an Address interface, and the implementation can be provided separately (e.g. provide an Address interface and an AddressImpl implementation). This will reduce the amount of binding between the core library and the library your developers will develop.
In this case Address is a part of a library which deserves its own jar. If you create a class named Address in my.Contacts, my.Appointments, and my.Location and you want to use all theses jar in a same application, you'll have a conflict for your Address class.
I suggest you don't "Deliver" these jars separately. Java has very subtle versioning issues that you don't want to run into. Build everything together and package it into one or two jars and always deliver both jars, or build them together and deliver a subset of jars (but never combine new and old jars--don't just try to send a single jar as an update).
If you must build them separately be very aware that final constants are compiled in and not referenced--so if you change one and deliver a new jar, any references from an older jar will not be updated.
Also method signatures that change will have strange, unpredictable results.
It sounds like you want a developer interface as well--that may be a set of interfaces and classes that reside in a separate jar. If you make that one jar well enough that you never have to rev it (and, of course, with no references to external constants) you can probably get away with not updating it which will keep your customer's extensions from getting crusty.

How can I override a class using a separate jar?

A customer requires a preview of a new feature of our product. They asked to have that feature sent to them in a jar file (like a patch). There's no problem with including the new classes in said jar file. However, an existing class was modified, which is needed to integrate the new feature. They just want to add this new jar file without having to update the core classes of our product. So, the question is: is it possible to override an already existing class using a separate jar? If so, how?
Thanks in advance.
There's a chance it'll work if you put the new jar earlier in the classpath than the original jar. It's worth trying, although it still sounds like a recipe for disaster - or at least, really hard to debug issues if somehow both classes are loaded.
EDIT: I had planned to write this bit earlier, but got interrupted by the end of a train journey...
I would go back to the customer and explain that while what they're asking is possible, it may cause unexpected problems. Updating the jar file is a much safer fix, with much less risk. The phrases "unexpected problems" and "risk" are likely to ring alarm bells with the customer, so hopefully they'll let you do the right thing.
Yes and no, it depends on your environment.
If you use, for example, OSGi and have your versions under control, it's just a matter of installing a new bundle with the exported package at a higher version (assuming your version ranges are lenient enough).
If you use plain old Java with no fancy custom class loading, you should be good to go putting it earlier on your class path (as others already mentioned).
If you do have custom class loading, you'll need to make sure that all the classes that your 'patched' class needs, and indeed the entire transitive dependency hull, is visible from the class loader which is loading the patched version, which might mean you need to ship the entire application, worst case.
All of the answers that stipulate putting the updated classes before the ones they are replacing in the classpath are correct, only provided the original JAR is not sealed or signed.
Yes, it may be possible, by putting it earlier on the classpath than your original jar. However, relying on the ordering of your classpath is not always going to lead to happiness. I'm not sure if it is even documented in the Java Language Spec; if not, then it's going to break for different JVMs and even different versions of the same JVM.
Instead, consider quoting a realistic time frame to integrate the new feature into the current codebase. This is perhaps not the answer you're looking for.
Probably more than you need for this specific case, but in generally if you just want to tweak or augment an existing class you can also use AspectJ with load-time weaving.

Categories