PropJoe
I have long had this irritating problem with .properties. It goes something like this:
- I like to use
.propertiesfiles for configuration unless there is a compelling reason to use something more complicated. - I'm pretty uptight about using constants in my code. This includes using constants to refer to the names of properties in a
.propertiesfile. - Over time, the constants and the
.propertiesfile can drift apart - you have to keep them both in sync. - Similarly, properly documenting them both becomes a painful
So, I proceeded to finally do something about it. I spent about 15 minutes writing the code and 45 minutes writing the documentation, go figure why. Maybe it's because The Wire is over and I think I just needed to do something to say goodbye. At any rate, I have found it has made my life just a little bit easier.
With that, I give you, PropJoe.
Package Description for PropJoe:
Provides a javadoc doclet for generating a .properties file
from annotated Java constants. This simplifies the task of maintaining
consistency and documentation between the .properties file
and Java code which references values in it.
Motivation
Properties files are ubiquitous. They're easy to use and everyone understands them. They are the way to go for relatively simple application configuration or to externalize program constants that might occassionally have to be changed in the field.
If your app has a .properties file with more than a couple of propertie in
it, you hopefully you are using constants in your code to refer to the names
of the properties. So, for example, you end up with a class that
holds a bunch of constants that you pass to getProperty()
when you need to get a property. Something like this:
public interface PropertyNames {
public String LISTEN_PORT = "listen.port";
public String BIND_ADDRESS = "bind.address";
public String FACTORY_CLASS = "factory.class";
//...
}
And then of course you end up with a .properties file like this that
you need to ship with your product.
# # acme product.properties # listen.port = 7001 bind.address = 127.0.0.1 factory.class = com.acme.AcmeFactoryImpl
This is all well and good and hopefully we can just assume that all of this accepted good practice. However, there are a few problems here:
Keeping the interface and the .properties file in sync
as the number of properties grows is problematic.
Also, documentation is similarly problematic. We can document the Java interface, which our developers will like. We can document the properties file, which our users will like. Or we can try to document them both and slowly go insane as the number of properties increases.
PropJoe
This is a basic single-sourcing problem, and it is this problem that PropJoe solves in two easy steps:
- Apply PropJoe's
@Propertyannotations to the constants on the Java interface - Run PropJoe javadoc doclet to generate a .properties files
To modify our example above, we'd have something like this on the Java side:
public interface PropertyNames { /** * The port that the server will listen on */ @Divider("Acme Product Properties") @Property("7001") public String LISTEN_PORT = "listen.port"; /** * The address the server server will bind to */ @Property("127.0.0.1") public String BIND_ADDRESS = "bind.address"; /** * Fully-qualified class name of the special acme factory to instantiate. */ @Property("com.acme.AcmeFactoryImpl") public String FACTORY_CLASS = "factory.class"; //... }
Which we could run through the PropJoeDoclet to get an output .properties
file like this:
############################################################## # Acme Product Properties # The port that the server will listen on listen.port = 7001 # The address the server server will bind to bind.address = 127.0.0.1 # Fully-qualified class name of the special acme factory to instantiate factory.class = com.acme.AcmeFactoryImpl
Now, there is no more synchronization problem between the two files, and the .properties file is nicely documented to boot. All we have to do is worry about a single Java file.
Running the Doclet
Run PropJoe like you would any other doclet. The only thing special about it is that it requires one doclet parameter, -f, to specify the path of the output properties file. Note that if the file already exists, the output will be appended to the file.
Also note that you can scan as may input Java files as desired for Property annotations - if you have those constants sprinkled all over your codebase, that's fine - just feed all of the source to javadoc and PropJoe will find them.
For example, from the command line you would simply
javadoc -doclet net.pcal.propjoe.PropJoeDoclet ... -f my/output/dir/product.properties
or in Ant using the javadoc ant task:
<javadoc packagenames='com.acme.product.*'
docletpathref='path.to.propjoe.jar'
failonerror='true'>
<fileset dir='bootstrap/src'>
<include name='**/PropertyNames.java'/>
</fileset>
<doclet name='net.pcal.propjoe.PropJoeDoclet'>
<param name='-f' value='my/output/dir/product.properties'/>
</doclet>
</javadoc>

Leave a comment