26

I have a web application in which the dependencies pull in two jars called:

  1. javassist-3.9.0.GA.jar
  2. javassist-3.20.0-GA.jar

when I package the WAR I have both of these in the WEB-INF/lib directory, my question is that the application is running and why I wouldn't get any issues because apparently I have same classes in both jars and there should be issues right?

Community
  • 1
  • 1
Toseef Zafar
  • 1,601
  • 4
  • 28
  • 46
  • 1
    If you really have two versions of the same artifact in your `war` you are doing something wrong...with default Maven and maven-war-plugin should never have a duplicate jar file in your lib folder....(it sounds you doing things manually which should left maven to do)... – khmarbaise Feb 13 '16 at 16:23
  • Thanks, if I am using 'package' goal to build the war file, is it not using maven war plugin to do that? if not, what different maven-war-plugin does to 'package' goal? – Toseef Zafar Feb 13 '16 at 16:31
  • `package` is not a goal it's a life cycle If you have set the correct `war` in your pom file this should work out of the box...Best would be to see the pom file you are using.. – khmarbaise Feb 14 '16 at 16:27
  • Possible duplicate of [How to include two different versions of the same dependency?](https://stackoverflow.com/questions/25989409/how-to-include-two-different-versions-of-the-same-dependency) – Flow Jun 19 '18 at 06:13

2 Answers2

34

For Java it doesn't matter how many versions of a class you provide. The default classloader will just pick the first one on the classpath it can find.

Since you can run the application without error this means one of the following:

  • if javassist-3.9.0.GA.jar is first on the classpath: your application doesn't rely on new APIs or bugfixes in javassist-3.20.0-GA.jar Also no APIs you used of this library changed between these versions (which a library shouldn't do between minor versions)

  • if javassist-3.20.0-GA.jar is first on the classpath: the library is backwards compatible

I suggest:

  • If these dependencies are direct dependencies in different parts of your application, make sure you're using everywhere the same version. The best way is to fix the version in the dependencyManagement section of the parent POM and then omit the version attribute in the dependencies sections.
  • If these dependencies are transitive dependencies, then exclude the one you don't want to use to make sure you only have one version of the library in your final application. Also consider to file an issue for the project that still uses the old version and ask them to upgrade the version of the dependency.
  • If you need to work with two incompatible versions of the same library, which have the same package and class names, consider to use a module system such as OSGi, which supports running different versions of the same library to some degree.
Puce
  • 37,247
  • 13
  • 80
  • 152
  • I understand that and its kind of a logical explanation to that, but doesn't that mean the application is really at risk because if I have a dependency which relies on a Class from 3.9.0.GA and that class was updated in 3.20.2-GA and also 3.20.0-GA is first and in classpath AND that dependency needs the version of that particular class in 3.9.0.GA ? – Toseef Zafar Feb 13 '16 at 16:15
  • 1
    Also another question is how to find out which one is first in the classpath? – Toseef Zafar Feb 13 '16 at 16:16
  • You can't find out which is the first one...This is a big issue in your app...You should fix this..otherwise your app could run and sometimes it will fail... – khmarbaise Feb 13 '16 at 16:24
  • @Puce, thanks for your help. I was able to get rid of the dependency I was manually putting in the POM, which leaves me dependent on dependency which relies on javaassist-3.20 but for now its all good! thanks – Toseef Zafar Feb 14 '16 at 12:26
  • @Tefa If you have somewhere a direct dependency to a library such as javaassist, it's still best practice to declare it as such. Just make sure the version matches the other transitive dependency to javaassist. – Puce Feb 14 '16 at 14:31
  • Identify why you have several versions of the given artifact in your app which implies there is going something wrong... – khmarbaise Feb 14 '16 at 16:28
  • @Puce 1) "Also no APIs you used of this library changed between these versions" - How can you be so sure? If, 3.9.0 is the first one to get loaded, what problem is going to arise if 3.20.0 has a different API signature in the same fully-qualified class. 2) "library is backwards compatible" - How can you be sure again? May be his application relied only on 3.20.0's APIs which might have a very different API signature than that of 3.9.0 / or even a completely different package and class name? – user104309 Jan 07 '17 at 21:56
  • @user104309 have a look at semantic versioning - an api should never change it's signature within minor versions, because minor versions need to be backwards compatible. – inetphantom Jan 08 '19 at 13:32
  • @user104309 because there were apparently no issues (no runtime errors etc.) – Puce Jan 09 '19 at 21:00
6

Answering to "any suggestions how to fix it?" take a look at Resolving conflicts using the dependency tree. With the command mvn dependency:tree you'll be able to know where any dependency comes from. When you know which artifacts depends on javassist, you may add an exclusion entry to avoid one of the javassist version.

polypiel
  • 2,321
  • 1
  • 19
  • 27