Package net.pcal.propjoe

Provides a javadoc doclet for generating a .properties file from annotated Java constants.

See:
          Description

Class Summary
PropJoeDoclet Doclet for generating .properties files by inspecting Property and Divider annotations on constants in a a class or interface.
 

Annotation Types Summary
Divider Annotation which will cause a section divider to be generated with the annotation's value as the section label.
Property Annotation which specifies a property to generated in the output properties file.
 

Package net.pcal.propjoe Description

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:

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>