views:

45

answers:

4

Hello,

I would like to include a default default.properties file in my .jar library. The idea is to allow the user to override my default is he so desires.

I'm having trouble getting the classloader to play nicely with this setup, I've tried to look a at popular jars such as log4j, common-* and others and it seems that no one is implementing this idea. Am I going the wrong way?

The second best thing is hard coding the values, and using the default if no .properties key has been found, but this sound oh so wrong.

Suggestions?

A: 

I find your design correct and good. log4j doesn't do that and I always curse them that I need to recall their configuration syntax and just cannot go with some nice defaults (I know BasicConfigurator, but it is too simple).

And I believe many web frameworks are bundling their default configuration in their jars.

What problems are you having with classloader?

pajton
A: 

you can either read the user configuration file from the classpath or from the file system.

the file system approach is to look in predetermined location (current directory, /etc/ or whatever) for the configuration file and if it's missing to read the one in the jar. you can even include a command to create a default configuration file (as a file).

the classpath approach is trickier, because your application is not in full control of it. the idea is that the location where the user is expected to locate his configuration file is to be BEFORE the jar itself in the classpath.

you can either have the user fiddle with the classpath (which is not a good idea) or ship your jar with suitable classpath (Class-Path entry in the manifest). I`m not sure if it's possible because I expect classpath entries in the manifest to be appended to the classpath and not prepanded.

Omry
A: 

You can use the ClassLoader to read in files that you have in your jar's classpath. For example, if you have a class Test, and you want to read a file that is in the same directory as your packages, you can use the following:

Test.class.getClassLoader().getResourceAsStream("test_file.txt")

You can parse that input stream using your standard readers:

new BufferedReader(new InputStreamReader( Test.class.getClassLoader().getResourceAsStream("test_file.txt") ))

Finally, if your file lives within one of your packages (com.test), you specify the path as follows:

 new BufferedReader(new InputStreamReader( Test.class.getClassLoader().getResourceAsStream("com/test/test_file.txt") ))
Chris J
A: 

I prefer to keep defaults and overrides in separate files.

Lets say you have a file mysettings.properties. I would split that into two. mysettings-default.properties and mysettings.properties.

The default one should be included in the jar file and shipped. The user can override the defaults by supplying mysettings.properties in various locations - like classpath, or current working directory, or user.dir or via a custom override -Dsettings.path=/path/to/file. This way, you have sensible defaults for the lazy, and a very flexible way to override when needed.

The code is pretty simple.

  1. Create a Properties object corresponding to mysettings-defaults
  2. Try loading mysettings from various locations. The first one wins. Load this in a separate properties object.
  3. Merge the two properties object. They are essentially maps, so addAll works. Just be careful with the order.

That's it! You have a highly configurable system with sensible defaults.

sri