CompileTimeCache
From APIDesign
Line 1: | Line 1: | ||
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. | 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 [[JDK]]6 and the help of [[AnnotationProcessor]]s, it is easier than ever. This article shows | + | However caches can also be created during compilation. With [[JDK]]6 and the help of [[AnnotationProcessor]]s, 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 [[AnnotationProcessor]]s 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: | ||
+ | |||
+ | <source lang="java" snippet="anagram.api.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: | ||
+ | |||
+ | <source lang="java" snippet="anagram.words.annotation.usage"/> | ||
+ | |||
+ | 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: | ||
+ | |||
+ | <source lang="java" snippet="anagram.api.WordsProcessor"/> |
Revision as of 12:35, 25 July 2009
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(); } } }