4

I am currently stuck in integrating Java packages because of a version conflict with BouncyCastle.

We have internally developed a component to handle data files sent to our local Revenue Service (not "the" IRS, but an equivalent tax authority in another European country) using official Java APIs provided and maintained by them. Another module of our platform uses a component from a Certification Authority to perform certified timestamping of files. Both have to be integrated into a single web application deployed at customer sites.

As you may know, BouncyCastle packages, on which both packages depend, have undergone several public API changes, so that consequent versions are no more binary compatible.

Revenue Service provides "cryptotools.jar" package which depends on the following:

<dependency org="org.bouncycastle" name="bcprov-jdk15on" rev="1.49"/>
<dependency org="org.bouncycastle" name="bcpkix-jdk15on" rev="1.49"/>

Certification Authority's provides "jades-kernel" timestamping package which depends on

<dependency org="org.bouncycastle" name="bcmail-jdk15"     rev="1.45"/>
<dependency org="org.bouncycastle" name="bcprov-jdk15"     rev="1.45"/>
<dependency org="org.bouncycastle" name="bcprov-ext-jdk15" rev="1.45"/>
<dependency org="org.bouncycastle" name="bctsp-jdk15"      rev="1.45"/>

Having both packages on classpath results in all BouncyCastle packages to be dumped into my WEB-INF/lib folder, which normally doesn't sound bad

Dependencies

But if I try to start the web application with all of these packages inside I get an Error saying that a class extends a final method. I won't post the stack trace, it's irrelevant for my question

If I remove any of the two versions (1.45 or 1.49) of BC, one of the modules won't compile. Well, they are both already compiled, so they won't simply link to their referenced classes/methods.

I have reported this situation to the CA (with which we have a maintenance contract for the Java APIs), using the older BC version (which has security vulnerabilities found by Black Duck, so that my customer is making my life painful). The CA is not cooperating yet. They would need to release a new version of their cryptography APIs compatible with more recent versions of BouncyCastle.

Me and my boss (C-level boss) are escalating the issue to CA hierarchy, and, according to our local humour, soon we will be escalating up to Francis

Mentioning humour, please allow me to share my current feeling in a visual fashion

Dependency hell in Java

Question time, now back to serious discussion

Suppose our vendor does not cooperate, or at least not timely for our regulatory deadlines. Revenue Service will not obviously downgrade their Java APIs to an older BC version.

How do we get out of this dependency hell? I know, for example, that log4j had a "bridge" package to mitigate breaking API changes between 1.x and 2.x versions for those packages who haven't upgraded yet. How do we make two modules coexist when they depend on different BC versions?

I will post a possible workaround but it's not our preferred solution.

Community
  • 1
  • 1
usr-local-ΕΨΗΕΛΩΝ
  • 26,101
  • 30
  • 154
  • 305

2 Answers2

3

Essentially Java is not built for this and Maven certainly isn't (as there is an underlying assumption that any newer version is a perfectly fine replacement for an older version when resolving these kind of conflicts).

It is my understanding that you have a monolithic application, so as you cannot physically split up the classpaths you can do it logically.

A way to handle this could be to run your application in multiple classloaders so that the jar files never "touch". I asked a "how to run in multiple classloaders" question earlier - Want to run non-threadsafe library in parallel - can it be done using multiple classloaders? - and this approach combined with loading a jar which is not on the classpath may be doable.

Thorbjørn Ravn Andersen
  • 73,784
  • 33
  • 194
  • 347
  • Essentially my application is a monolithic web application, correct! – usr-local-ΕΨΗΕΛΩΝ May 26 '17 at 09:10
  • Web application? Then you might be able to split into /a and a private /b where /b is doing the small section where the older jar is needed and have /a talk to /b using normal web requests. – Thorbjørn Ravn Andersen May 26 '17 at 09:12
  • That's exactly the workaround I proposed in my own answer (will fixup the wording). It's not beautiful, and can't be done in short time. But at least makes the gears work. – usr-local-ΕΨΗΕΛΩΝ May 26 '17 at 09:15
  • To be more clear: requesting a customer to allocate us a different web application context is paperwork for both, and (as I said) won't fix the security issue of having outdated dependencies. But that is obviously out of the question scope, as if the vendor does not cooperate upgrading BC there is nothing my company can do other than be paid to rewrite the vendor code from scratch. I need to consider all of my alternatives – usr-local-ΕΨΗΕΛΩΝ May 26 '17 at 09:18
  • 2
    To my experience you cannot expect vendors to update to newer versions of a library (which might break all their stuff) just because you ran into a problem which is not their fault. I would suggest backporting your troublesome module - for which you have the source - to the version of BC you have to use. – Thorbjørn Ravn Andersen May 26 '17 at 09:22
  • No... our module depends on an tax service module which depends on outdated BC. We don't have direct dependencies to BC (fixing up question if needed). Basically vendors are two: revenue service and CA – usr-local-ΕΨΗΕΛΩΝ May 26 '17 at 09:23
  • Then separate classloaders is your only option to my knowledge. I would investigate very carefully if I were you how your specific container works because there might be issues you need to be aware of as you are essentially looking into bending the servlet specification. – Thorbjørn Ravn Andersen May 26 '17 at 09:25
1

A workaround may be to split up the web application into multiple applications each deployed in a different context and communicating via web service. The secondary applications will be just private.

The timestamping module will have its classpath with older BC version, and the tax service module will have a different classpath. The "main" front end web application won't have any dependency to BC at all.

This doesn't solve the Black Duck issue because the customer will mandate an upgrade or require a lot of paperwork to allow a policy exception.

usr-local-ΕΨΗΕΛΩΝ
  • 26,101
  • 30
  • 154
  • 305