'

Writing and processing custom annotations - Part 4

Check out the final part of this series of articles on annotations.

We have finally arrived at our last and final part of this series of articles on annotations.

In the previous three articles (part 1, part 2 and part 3), we saw how to design and develop a custom annotation; we also looked at how to write a processor to handle the custom annotation. Now we come to the part where we put all these elements together and see how to use them. Finally, if you are interested in developing this @Option annotation further, I'll give some suggestions at the end of this article.

Using the @Option Annotation
In the first article are details on how to use the @Option annotation and generate the option processor, so I will not repeat them here. I will, however, talk about packaging and environment settings.

  1. The easiest way to distribute our annotation and its corresponding processor is to package it in a JAR file. Generally you package the annotation class, the annotation processor class and all utility classes used by the processor. In our case, we have only 2 classes to package, options.Option.class and options.OptionProcessor.class
  2. When you are annotating your option bean with the @Option annotation, you have to either add the annotation JAR to your CLASSPATH environment variable or as a classpath parameter when you are compiling the option bean.
  3. Now, when you are generating the option processor class, you have to again either include the annotation JAR in your CLASSPATH environment variable or use-classpath option to javac. You will also need to specify the name of the processor class by using the -processor option. Unfortunately at the time of writing, this option has yet to be documented on the official Java 6 (a.k.a Mustang) Javadocs. Below is an example of using -processor option:

javac -processor options.OptionProcessor -classpath ./options.jar \
   FileTransferOptions.java

The FileTransferOptions.java is our option bean; the options.OptionProcessor is our option processor fully qualified class name. Note that we use-processor to specify the option processor class to use. Assume that options.jar is where we package the annotation and processor class.
The class FileTransferOptionsProcessor will be generated after the compilation. You can now use this class to process all the option switches defined in FileTransferOptions. Again see the first article on how you use this.

Going Further
The options processor developed in this series of articles is quite simplistic. If you are interested in developing it further, here are some ideas:

  1. Error checking is not done on the option switches. The generated option processor will just ignore any switches that it did not understand. Add error handling so that the option processor will print out the list of options and its corresponding help string, if any, when it encounters an error.
  2. Auto generate a help switch (-help) so that it will print out the list of supported options and its corresponding help string, if any.

java Main -help
The options are
   -filename - Text file name
   -config - Configuration file
   -server

  1. Currently the option processor only supports String; rewrite the option processor so that it supports all primitive types. The option processor should look at the type in the option bean and automatically convert the option value to the corresponding type. Here is an example:

public class MyOptions {
   @Option(name="-filename") public String fileName;
   @Option(name="-copies", help="Number of copies") public int copies;
   @Option(name="-header", help="Print header? y|n") public boolean printHeader;
   @Option(name="-printer") public String printServer;
}

Now if we type the following

java Main -filename fred.txt -copies 2 -header n -printer myprinter

then 2 and n will be converted to the integer value 2 and false respectively.

  1. Support for multi-valued options. In the code snipped below -filename is multivalued; this is inferred from the String array

public class MyOptions {
   @Option(name="-filename") public String[] fileName;
   @Option(name="-copies", help="Number of copies") public int copies;
   ...

The following are two ways of how you specify multivalued options:

java Main -filename fred.txt barney.txt -header n -printer myprinter

or

java Main -filename fred.txt -filename barney.txt -header n -printer myprinter

  1. Regular expression support

public class MyOptions {
   @Option(name="^-[Ff][Ii][Ll][Ee][[Nn][Aa][Mm][Ee]]*", re=true) public String[] fileName;
   @Option(name="-copies", help="Number of copies") public int copies;
   ...

The following are then valid options

java Main -FileName fred.txt -file barney.txt -header n -printer myprinter

  1. If there is anything else you care to implement, here are some suggestions: validators, mutually exclusive options and option switch only viz. specify -debug to enable the debug option instead of -debug y

Lee Chuk-Munn has been programming in the Java language since 1996, when he first joined Sun Microsystems in Hong Kong. He currently works as a senior developer consultant and technology evangelist for Technology Outreach at Sun in Singapore. Chuk's focus is in Java APIs, Java EE, Java SE, and Java ME. Chuk graduated in 1987 from the Royal Melbourne Institute of Technology in Melbourne, Australia, where his favorite subject was compiler theory.