PropJoe

| | Comments (0)

I have long had this irritating problem with .properties. It goes something like this:

  • I like to use .properties files 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 .properties file.
  • Over time, the constants and the .properties file 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.

Download propjoe-0.1.0.zip


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 @Property annotations 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

About

My name is Patrick Calahan.

I live in San Francisco.

I do product development and consulting on Java and Business Intelligence.

This is my blog.

Contact

About this Entry

This page contains a single entry by published on March 18, 2008 12:40 AM.

Create a custom .EXE to launch Tomcat was the previous entry in this blog.

Find recent content on the main index or look in the archives to find all content.

Powered by Movable Type 4.01