CompileTimeCache

From APIDesign

Revision as of 12:35, 25 July 2009 by JaroslavTulach (Talk | contribs)
Jump to: navigation, search

Caches are usually created during installation time or during first execution/computation. Just like the CacheForModularity, they provide another store for information available elsewhere. This store is easily accessible, faster to read and use which then results in more optimal execution.

However caches can also be created during compilation. With JDK6 and the help of AnnotationProcessors, it is easier than ever. This article shows general principles and describes few tools that can make the task even simpler. Let's describe yet another variant of Component Injection, by rewriting the Anagram Game as introduced in Chapter 7.

Define the Annotation

Although not necessary, it is good to define an annotation in your API. At the end AnnotationProcessors are optimized to process annotations. To allow API users to easily define list of words to feed into the Anagram game, let's introduce @Words annotation:

Code from Words.java:
See the whole file.

@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.METHOD)
public @interface Words {
}
 

Any user will be allowed to annotation its own static method with this annotation instructing the API to call this method whenever somebody needs a list of words to play the anagram game. Here is a sample use:

Code from WordsFactory.java:
See the whole file.

public class WordsFactory {
    @Words
    public static String[] myWords() {
        return new String[] {
            "microprocessor",
            "navigation",
            "optimization",
            "parameter",
            "patrick",
        };
    }
}
 

Please note that although this example is quite simple (and there are usually more complicated annotations), it already simplifies the use of the API compared to original ServiceLoader based alternative - one does not need to implement any factory interface, just provide a method and annotate it.

Compiler Plugin

The @Words annotation has RetentionPolicy.SOURCE. This means that it shall not propagate to resulting bytecode or be present in runtime (via reflection API). Instead it needs to be processed during compile time via AnnotationProcessor. Is it complex to define one? Not at all, just write:

Code from WordsProcessor.java:
See the whole file.

@ServiceProvider(service=Processor.class)
@SupportedAnnotationTypes("org.apidesign.anagram.api.annotations.Words")
@SupportedSourceVersion(SourceVersion.RELEASE_5)
public class WordsProcessor extends LayerGeneratingProcessor {
 
    @Override
    protected boolean handleProcess(
        Set<? extends TypeElement> set, RoundEnvironment env
    ) throws LayerGenerationException {
        Elements elements = processingEnv.getElementUtils();
 
        for (Element e : env.getElementsAnnotatedWith(Words.class)) {
            Words w = e.getAnnotation(Words.class);
 
            TypeElement te = (TypeElement)e.getEnclosingElement();
            String teName = elements.getBinaryName(te).toString();
}
}
}
 
Personal tools
buy