views:

125

answers:

4

I have a program that needs several third-party libraries, and at the moment it is packaged like so:

zerobot.jar (my file)
libs/pircbot.jar
libs/mysql-connector-java-5.1.10-bin.jar
libs/c3p0-0.9.1.2.jar

As far as I know the "best" way to handle third-party libs is to put them on the classpath in the manifest of my jar file, which will work cross-platform, won't slow down launch (which bundling them might) and doesn't run into legal issues (which repackaging might).

The problem is for users who supply the third party libraries themselves (example use case, upgrading them to fix a bug). Two of the libraries have the version number in the file, which adds hassle.

My current solution is that my program has a bootstrapping process which makes a new classloader and instantiates the program proper using it. This custom classloader adds all .jar files in lib/ to its classpath.

My current way works fine, but I now have two custom classloaders in my application and a recent change to the code has caused issues that are difficult to debug, so if there is a better way I'd like to remove this complexity. It also seems like over-engineering for what I'm sure is a very common situation.

So my question is, how should I be doing this?

A: 

You can try the Fat-Jar solution, it works perfectly with the 'Fat Jar Eclipse Plug-In'. I have used for a few projects with no problems at all. The principle of it seems to be the same of your current solution.

bpfurtado
If I'm reading that right it just handles the packaging for my distribution, and not for users upgrading their external libraries?
ZoFreX
@bpfurtado: +1, or use "izpack"... Or do the same yourself, it's not hard.
Webinator
fat-jar is just about packaging and it does not provide a upgrading mechanism for the included libraries. Regarding your difficulties to dubug using a custom Classloader, I just do all development/debugging inside my IDE and after that I use fat-jar to make the deployment, all tests left to make with the 'packed' solutiuon would be related to 'ClassNotFoundException's, what never happens, since 'fat-jar' works pretty well.
bpfurtado
I haven't tested Fat-Jar but many methods of repacking everything into one jar can slow things down. It's also worth noting that repackaging like this is often not allowed by the licenses of third party libraries, especially if the application itself is not under the same license (in my case it is not open source).
ZoFreX
Slow things down? How? You mean something like the application startup time? Because I don't see it slowing the development time.Regarding licenses, you'll have the problem no matter the technical solution you use... I thought you wanted a technical solution. Fat-Jar does exactly what you tried to do yourself, but it's pretty stable, I never saw it crashing and I used it a lot. You don't need to 'reinvent the wheel', that way you can focus on your application unique features ;)
bpfurtado
I mean startup time, not development time. Some licenses allow bundling but not repacking, if they don't allow bundling then other approaches listed here will let the end-user drop them in themselves. It's a neat solution for some situations, but it doesn't meet my main criteria (upgrading).
ZoFreX
+2  A: 

We provide script files with the jar. E.g. some.bat, some.sh etc.

And as of Java6, you can use wildcard to specify classpaths.

Here is a good article that explains this approach : http://blogs.sun.com/mr/entry/class_path_wildcards_in_mustang

Enno Shioji
@Zwei steinen: he wants to be cross platform. Java 6 means you'd cut yourself from a huge part of the OS X userbase which have Macs that shall never officially have Java 6 (32 bits CPU Macs).
Webinator
Ehhhh for this project OS X compatibility isn't really a biggy, and I've been compiling against 1.6 anyway. Thanks for the tip though, I will have to check that my other projects work on 1.5!
ZoFreX
I'm going to specify the classpath in the jar manifest and require that the end-user names third party libraries correctly when they upgrade them. However, I'm marking this one as accepted as it had the most cool information.
ZoFreX
A: 

I think I'm going to go the manifest route. Declare the classpath in the manifest for the entry jar, and have entries for:

libs/pircbot.jar
libs/mysql-connector-java-5-bin.jar
libs/c3p0.jar

Then if users want to upgrade to the latest library versions, they will have to rename them to match what is declared in the manifest. I don't think that's too big a hassle, and it makes things a lot simpler internally.

I also just generally don't like the idea of loading everything in ./lib/ automatically, that seems potentially dangerous.

ZoFreX
+1  A: 

If your audience is technical (and it sounds like they are if they're willing to drop in new jar files) then perhaps you could supply .sh and .bat files that they can edit to modify the classpath? That will be more transparent to them than a custom classloader.

Brian Slesinsky
This isn't a bad approach but it does complicate things when they update the main program jar, as their changes would need to be re-done. I think overall requiring them to rename the files is the best approach, but if there are complaints I will probably go down this route.
ZoFreX