Search code examples
javaclassloader

How to create a custom ClassLoader for nested JAR files


I am working with a Java library that has some nested JAR files in lib package.

I have 2 issues:

  1. I cannot see referenced types in my IDE (I am using JetBrains IntelliJ)
  2. Of course I get class not defined at runtime

I understand that I have to create and use a custom ClassLoader, will it solve both problems?
Is this the recommended way of achieving this result?

The JAR file is an Italian government provided library and I cannot modify it as it will be periodically updated as the regulation changes.


Solution

  • Yes, as far as I know, the standard ClassLoaders do not support nested JARs. Which is sad, since it would be a really nice idea, but Oracle just doesn't give a damn about it. Here is a 18-year old ticket:

    https://bugs.java.com/bugdatabase/view_bug.do?bug_id=4735639

    If you are getting those JARs from somebody else, the best thing would be to contact the vendor and ask them for a delivery in standards-compatible format. From your answer I realize that this might be difficult to achieve, but I would still try to talk to them, because it's the right thing to do. I'm pretty sure that everybody else in your position has the same issue. According to industry standards, such situation would usually hint your vendor into using Maven repository for their deliverables.

    If talking to your vendor fails, you can re-pack the JARs as you get them. I would recommend writing an automated script for that and making sure it gets run on each delivery. You can either put all .class files into one uber-JAR, or just move the nested JARs outside the enclosing JAR. Caveat 1: there can be more than one class with the same name, so you need to make sure to take the correct one. Caveat 2: if the JARs were signed, you will lose the signature (unless you sign them with your own).

    Option 3: you can always implement your own ClassLoader to load the classes from anywhere, even from the kitchen sink.

    This guy did exactly this: https://www.ibm.com/developerworks/library/j-onejar/index.html

    The short summary is that such a ClassLoader has to perform recursive unzipping, which is a bit of a pain-in-the-ass because archives are essentially made for stream access and not for random access, but apart from that it's perfectly doable.

    You can use his solution as a "wrapper loader" which will replace your main class.

    As far as IntelliJ IDEA goes, I don't believe it supports this functionality out-of-the box. The best thing would be either to re-package JARs as described above and add them as separate classpath entries, or to search if anybody has written a plugin for nested JAR support.