views:

1031

answers:

3

Hello,

I'm looking to do something which I thought was not going to be difficult.

I have an application that I'd like to package up as a jar because I've got ~30 dependencies and I would like to be able to deploy a single file.

I have some configuration files - a properties file and a spring configuration file, and my log4 props file - that I would like to have external to the jar. I guess I expected that if I put them in the same directory as the jar it would find them when it ran, but it doesn't.

While developing, I have these files at the root of the classpath for my eclipse project and the app finds them just fine. I feel like I'm missing some key aspect of jar / classpath theory...

so what I want is to be able to put the config files and the jar in the same directory and have the app find the config files when I run it with the standard java -jar thing.

Is there not a simple way to achieve this?

+1  A: 

You need to add "." to the classpath of the jar file you are building for your application.

So in the manifest, I'd expect to see

Main-Class: some.full.Name
Class-Path: . needed-lib.jar other-lib.jar 

Then, when you run your app by executing

java -jar myapp.jar

it actually uses

java -classpath .;needed-lib.jar;other-lib.jar some.full.Name

This way any file in the directory with the myapp.jar file will also be on the classpath. That classpath is relative to the location of jar containing it.

Log4j for one expects the log4j.xml configuration file to be on the classpath. If you aren't using the name log4j.xml you also have to add a system property to your start up command to tell the log4j library to look for a different name.

I'm not sure what Spring expects for configuration files. And property file loading depends on what mechanism is used to load the file. Using a FileReader or InputStream doesn't use the classpath mechanism at all. In that case you need to know where the application is expecting the file to be relative to the current working directory.

Jay R.
Thanks for the reply Jay R. My Manifest does have this in it, which I think is what you're suggesting:Manifest-Version: 1.0Main-Class: <my main class>Class-Path: .
Joel
I added more to my answer which I hope helps.
Jay R.
Thank you again for you reply Jay R. Your help is much appreciated.I am however not having much luck. I am using the log4j.properties file rather than the xml configuration, but I think as long as the file is on the classpath log4j should find it just fine.Same deal with the spring configuration file - I'm calling mine spring.xml but as long as it's on the classpath there shouldn't be any problems. My MANIFEST.MF is being generated by Eclipse's "Runnable Jar..." exporter but it looks exactly like your sample one.I'm not sure what's going on here. Thanks again for your insight.
Joel
Does the log4j.configuration file work if you include it inside the jar file?
Jay R.
Just to be clear, I am using the log4j.properties file, but yes it does work when included in the jar itself. My other configuration files (like the spring config file) also work when bundled into the jar. When not bundled into the jar, the spring context throws a FileNotFound exception because it can't find the spring configuration file.Thanks again for your insight. I appreciate it very much.
Joel
If you run it on the command line using the java -classpath <your classpath> <mainclass> does the log4j.properties file load properly? The classpath paths have to be separated by ; instead of a space, but otherwise is the same.
Jay R.
haha Jay R I hadn't seen this comment and came to the same conclusion myself. I added my 'answer' before I read your comment. Thank you so much for sticking with me so long. You really helped me out on this. Also I haven't tried this yet, but I'm not sure if the classpath parts can be separated by ';' on UNIX as well as Windows. I think on UNIX it's a ':' character. ??
Joel
I believe that is true.
Jay R.
+1  A: 

I think that you can do this with a manifest in the jar to specify the classpath that it should use.

Edited: somthing like This

phatmanace
A: 

I will preserve for posterity my solution to this problem.

I think it's possible that I was expecting java -jar to do something it doesn't do.

If you use the regular java command you can include the jar on the classpath and you'll end up with pretty much the same thing as java -jar, only you have to specifically name the class you want to use. It looks like this:

java -cp .:path/to/Jar.jar com.company.package.Class arg1=val1 arg2=val2 ....

Chances are you're going to build a script to start the program for you anyway, so the added complexity of the command line call doesn't really amount to much, since you'll only build it once anyway.

You'll see I included '.' as the first item on the classpath, which means anything in the same directory as the jar will be included on the classpath as well. Of course everything inside the jar is included on the classpath also, since the jar itself is on the classpath too.

You'll also see that I've shown how you can still hand in args on the command line. This was something I was unsure about when I started but it works as expected.

I'm sure this is just basic java deployment knowledge, but I was lacking it for some reason.

I hope this helps someone else. It certainly would have saved me a lot of time if someone had been able to say "don't bother trying to get the -jar thing working - just use the -cp method"...

Joel