9

I have a legacy web app running in Tomcat 5.0.

This web app has two jars in WEB-INF/lib, let's say Foo-2.0.jar and Bar-2.0.jar. Bar-2.0.jar actually includes a Foo-1.0.jar inside of it. Bar is also a dead project, meaning no upgrading, no source, but still important to the application.

The latest release of this application requires Foo-2.0.jar for some other stuff. Having both Foo-1.0.jar and Foo-2.0.jar in the classpath creates a conflict, specifically a ClassDefNotFound type of error, where a class that was later added in 2.0 cannot be found in 1.0, etc.

In Eclipse, the simple solution is to right click on your Project, click Properties > Java Built Path > Order and Export and to move Foo-2.0.jar above Bar-2.0.jar so it's resolved first.

How does one accomplish this type of classpath ordering for jars in WEB-INF/lib in Tomcat?

Robert Campbell
  • 6,848
  • 12
  • 63
  • 93

7 Answers7

34

Tomcat 5's classloading precedence for webapps is roughly as follows: first the bootstrap/system (JRE/lib, then Tomcat's internal classes), then the webapp libraries (first WEB-INF/classes, then WEB-INF/lib), then the common libraries (first Tomcat/common, then Tomcat/lib) and finally the webapp-shared libraries (Tomcat/shared).

So to get Foo-2.0.jar loaded before Bar-2.0.jar, best what you can do is to move Bar-2.0.jar from WEB-INF/lib to Tomcat/common or Tomcat/shared.

The JAR's aren't loaded in alphabetic order of their name. At least, there's no spec which says that. Renaming them to change the alphabetical filename order makes no sense.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Georgy answered first, so I accepted his submission, but what you describe is exactly what I did to resolve the problem. Your link was especially helpful. **I encourage everyone to vote up this answer**. – Robert Campbell Jan 07 '10 at 16:49
  • 1
    You're welcome. Although I would point out that answers here are **not** by default ordered by answer date. At the moment of writing you can see at the topright of the user avatar that I answered this question 23 minutes ago and Georgy 15 minutes ago. You can change the ordering by one of the three tabs `oldest`, `newest` and `votes` righttop of the answers. The default is `votes`. – BalusC Jan 07 '10 at 17:00
  • 1
    And, in the tooltip you can see the exact time. So I was actually first :o – BalusC Jan 07 '10 at 17:33
  • Class Loader HOW-TO for Tomcat 8 https://tomcat.apache.org/tomcat-8.0-doc/class-loader-howto.html – Sergey Ponomarev Jul 23 '15 at 13:04
4

Strip Foo-1.0.jar out of Bar-2.0.jar. As it is, it's just trouble waiting to happen both for development(need to fudge the dev. environments) and for deployment.

David Soroko
  • 8,521
  • 2
  • 39
  • 51
  • I really think this is the best suggestion. Repackage your bar-2.0.jar, otherwise you are just asking for headaches down the road. – Greg Case May 17 '10 at 19:09
3

Put Foo-1.0.jar to $CATALINE_HOME/common/endorsed (or any other place where it will be loaded after Foo-2.0.jar).

Georgy Bolyuba
  • 8,355
  • 7
  • 29
  • 38
1

You don't, as this feature isn't available in Tomcat. If both Foo-1.0.jar and Foo-2.0.jar are needed in the classpath at the same time, you will need some major classpath reorganization.

If Bar-2.0 can work with Foo-2.0, then the best thing to do would be to rebuild Bar-2.0 yourself without a Foo-1.0.jar inside of it.

jsight
  • 27,819
  • 25
  • 107
  • 140
  • There is no way to know if Bar-2.0 works with Foo-2.0 or not, and it's a massive, binary-only library with no test cases. – Robert Campbell Jan 07 '10 at 15:48
  • I believe the solution you are using has Bar-2.0 running with Foo-2.0, just in a kind of roundabout way. – jsight Jan 08 '10 at 15:09
0

It is possible to set the Class-Path in the mainfest of the jar. http://java.sun.com/developer/Books/javaprogramming/JAR/basics/manifest.html I can't really promise it will solve the problem, but can be worth a try.

Kennet
  • 5,736
  • 2
  • 25
  • 24
0

To have Foo-2.0.jar before Bar-2.0.jar, update the Bar-2.0.jar with the content of Foo-2.0.jar (overwrite already contained .class)and delete Foo-2.0.jar from the war.

-cp A.jar:B.jar has the effect, that content of A.jar is like a layer over B.jar. So you get the same effect with overwriting B.jar's content with A.jar's.

weberjn
  • 1,840
  • 20
  • 24
-2

This is a bit hacky but might work. Change the name of Foo-2.0.jar to be alphabetically ahead of Bar-2.0.jar, say AFoo-2.0.jar.

Vinodh Ramasubramanian
  • 3,157
  • 1
  • 20
  • 17