A practical approach to introducing conflicting jar libraries in monoliths.
When working on enterprise software we often encounter big monolith applications that are very hard and costly to maintain. This represents many challenges we are all familiar with, like longer development cycles, test automation is harder to accomplish, regressions are more difficult to detect, etc.
One of the cases I’ve worked with is SAP Commerce Platform which is in the millions of lines of code, but this solution applies to any java based Monolith and potentially C# (wink).
When introducing a new feature you may need to download and use certain dependencies, but what happens when conflicting libraries are already loaded and used within the application? what if they are older versions and can’t be upgraded easily? What if your dependencies can’t use those older libraries?
I’ll give you an example:
Say you have in your application that has a feature called Messages that depends on multiple libraries and one of them is Guava 1.0 as shown here:

Now you want to introduce a new feature called Storage that depends on Guava 2.0. What will happen is that you application will compile successfully but conversely on runtime will fail. This is a how the calls from each feature would look like (for simplicity assuming the call is for a class/method that exists in both versions):

This means that you’ll find out there is a potential issue only during runtime and not at compilation time, which might be very hard to detect.
Solution:
The solution requires to adapt the application to use multiple class loaders so that when the Storage feature tries to get a class, it first tries to get it from its own class loader and afterwards it reaches from the default class loader. So, the final solution looks like this:

Approching the problem this way will allow you to add as many dependencies without worrying of the potential unexpected side effects that can be very hard to detect. The downside is that it requires to load classes using reflection but usually it does not entails too much effort.
The final solution will require a bit of a understading on how the Class Loader works and some Reflection but I won’t go into those details here. But, If you want to know more about the implementation details I’d recommend reading this article, which will help you go into the weeds of how the class loaders work and what a child first loader looks like.
Does the monolith you work with offer a more flexible way to solving this problem? Please share!
Thanks for reading this article, I hope this is useful to you!

Leave a comment