Saturday, August 04, 2012

Jar Hell

I recently was called in to help troubleshoot an application. It was a java web app: a war. When I looked inside the WEB-INF/lib directory, here is what I saw:
  1. activation-1.1.jar
  2. asm-3.1.jar
  3. axiom-api-1.2.12.jar
  4. axiom-dom-1.2.12.jar
  5. axiom-impl-1.2.12.jar
  6. axis-1.1.jar
  7. axis2-adb-1.6.1.jar
  8. axis2-codegen-1.6.1.jar
  9. axis2-kernel-1.6.1.jar
  10. axis2-mtompolicy-1.6.1.jar
  11. axis2-transport-http-1.6.1.jar
  12. axis2-transport-local-1.6.1.jar
  13. axis2-xmlbeans-1.6.1.jar
  14. commons-beanutils-1.7.0.jar
  15. commons-beanutils-core-1.7.0.jar
  16. commons-codec-1.3.jar
  17. commons-collections-3.2.jar
  18. commons-configuration-1.2.jar
  19. commons-digester-1.7.jar
  20. commons-discovery-0.2.jar
  21. commons-fileupload-1.2.jar
  22. commons-httpclient-3.0.1.jar
  23. commons-lang-2.1.jar
  24. commons-logging-1.0.4.jar
  25. commons-logging-api-1.0.4.jar
  26. dac-client.jar
  27. dealer-locator-pojos.jar
  28. DealerLocatorWebServices-client-1.1.4.jar
  29. dom4j-1.4.jar
  30. ehcache-core-2.3.0.jar
  31. ehcache-web-2.0.3.jar
  32. ejb-api-3.0.jar
  33. httpcore-4.0.jar
  34. isorelax-20020414.jar
  35. jackson-core-asl-1.7.1.jar
  36. jackson-jaxrs-1.7.1.jar
  37. jackson-mapper-asl-1.7.1.jar
  38. jackson-xc-1.7.1.jar
  39. javax.ejb_3.0.1.jar
  40. javax.jms.jar
  41. jaxb-api-2.2.2.jar
  42. jaxb-impl-2.2.3-1.jar
  43. jaxen-1.1.1.jar
  44. jaxrpc.jar
  45. jersey-core-1.6.jar
  46. jersey-json-1.6.jar
  47. jersey-server-1.6.jar
  48. jettison-1.1.jar
  49. log4j-1.2.8.jar
  50. mex-1.6.1-impl.jar
  51. msv-20020414.jar
  52. neethi-3.0.1.jar
  53. ojdbc6.jar
  54. opensaml-2.2.3.jar
  55. pagination-lib.jar
  56. quartz-1.6.6.jar
  57. quartz-1.7.2.jar
  58. rampart-core-1.6.1.jar
  59. rampart-policy-1.6.1.jar
  60. rampart-trust-1.6.1.jar
  61. relaxngDatatype-20020414.jar
  62. saxpath-1.0-FCS.jar
  63. service-pojos.jar
  64. slf4j-api-1.5.11.jar
  65. slf4j-jdk14-1.6.1.jar
  66. stax-api-1.0-2.jar
  67. stax-api-1.0.1.jar
  68. tbgv2util.jar
  69. TMSFramework-2.2.46.jar
  70. TMSIntegrationFramework-0.0.216.jar
  71. TMSMessagingFramework-0.0.11.jar
  72. TMSUserMgmtFramework-
  73. warranty-maintainence-pojos.jar
  74. wiztools-commons-lib-0.2.0.jar
  75. woden-api-1.0M9.jar
  76. woden-impl-dom-1.0M9.jar
  77. wsdl4j-1.6.2.jar
  78. wss4j-1.5.12.jar
  79. xalan-2.7.0.jar
  80. xercesImpl-2.2.1.jar
  81. xml-apis-1.0.b2.jar
  82. xmlbeans-2.2.0.jar
  83. XmlSchema-1.4.7.jar
  84. xmlsec-1.4.5.jar
  85. xmltooling-1.2.0.jar
I, myself, have never created an application that uses 85 jars.

Making things worse, the app was running on a heavy weight app server (Web Logic) that added many more classes to the classpath, classes that do not show up in the above list. These included the entire stack of J2EE classes. Plus other classes that WebLogic thinks you might need.

Problem: Any app with this many classes in the classpath will surely have some accidental duplicate classes, possibly even multiple versions of the same class. This can be the source of very hard to track bugs.

This was, in fact, the source of the bugs in this particular application.

Moving forward, I would recommend the following:
  1. Add libraries and jars to your app very judiciously.
  2. Be careful of build tools that might recursively suck in unneeded library dependencies.
  3. Beware of any 3rd party libraries that require a whole bunch of other 3rd party libraries to work.
  4. When a 3rd party library comes with 10 other 3rd party libraries that it depends on, those other libraries might be optional libraries and not needed for your app.
  5. Avoid app servers that litter the classpath with unneeded libraries. 
  6. Be especially cautious of putting classes in your app servers global (cross-web-app) lib folder.
  7. This entire problem starts to goes away as we move toward a more micro-service style architecture.

1 comment:

Philip Yurchuk said...

That seemed like a lot of jars, but I looked at a relatively basic app I have and it clocked in at 59 jars. Part of this is Spring, which I know you're not a fan of. Another issue is a trend in bigger open source projects favoring breaking up jars so you have to include more of them, but overall you're including less code than when they were bundled and inseparable. Technically, dependency managers should reduce some of the duplication, but you're relying on a 3rd party set of metadata. Reviewing what they include is a good idea. I've had projects break because Ivy grabbed unnecessary dependencies. That's another thing - I try to use dependency databases directly from the source, which hopefully cuts down on that, as well as specify versions whenever it makes sense.