On Processors,Compilers and@ConfigurationsMichael PellatonNetcetera189
AGENDA> Spring @Configuration classes> An Annotation Processor for Validation> Unit Testing the Annotation Processor      ...
Code ExamplesThe code in this presentation is simplified and doesn’t compile.Full length, compiling version of the code:ht...
Spring @Configuration Classes> Java-based Spring application context configuration> An alternative to XML or annotation ba...
Let’s Read the Javadoc…          Must not            Must have a visible           be final           no-arg constructor  ...
What If There’s Something Wrong?Exception in thread "main" org...BeanDefinitionParsingException: Configuration problem: @C...
Your Developers                  7
Annotation Processors> Annotations can be processed at  – Runtime  reflection (methods on Class, Method & Co)  – Compile ...
JSR-269 Annotation Processors> A Java compiler plugin> An implementation of Processor> Interacts through ProcessingEnviron...
The Validating Annotation Processor@SupportedSourceVersion(SourceVersion.RELEASE_7)@SupportedAnnotationTypes(value = "org....
The Validating Annotation Processorpublic boolean process(Set<? extends TypeElement> annotations,     RoundEnvironment rou...
The Validating Annotation Processorprivate void processElement(TypeElement typeElement) {    for (AnnotationMirror ann : t...
The Result             13
The Result$ mvn clean compile...[ERROR] Failed to execute goal ...: compileCompilation failure:[ERROR] /.../ExampleConfigu...
Your Developer                 How about                 unit testing                 your code?                          ...
The Java Programming Language Compiler API> Idea: A unit test that compiles (faulty) classes and checks  the compiler outp...
The Java Compiler API : Main Components> The JavaCompiler is the  – interface to the Java compiler  – Factory for Compilat...
The Java Compiler API : Main Components                         ToolProvider                                creates       ...
Compiling Classes in Unit Tests for Processors/** Tests the detection of final @Configuration classes. */@Testpublic void ...
Compiling Classes in Unit Tests for Processorspublic static List<Diagnostic> compileClass(String clazzName,    Processor p...
Compiling Classes in Unit Tests for Processors    // compile the class and return the result    CompilationTask task = com...
The Result             22
Conclusion> Annotation processors can be used to extend the tooling and build beyond the  traditional purposes like code g...
Michael Pellaton    www.netcetera.comNetcetera           michael.pellaton@netcetera.chExamples & Links:   github.com/pella...
Upcoming SlideShare
Loading in …5
×

On Processors, Compilers and @Configurations

2,205 views

Published on

Jazoon talk on Java Annotation processors

Published in: Technology, Education
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,205
On SlideShare
0
From Embeds
0
Number of Embeds
141
Actions
Shares
0
Downloads
8
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

On Processors, Compilers and @Configurations

  1. 1. On Processors,Compilers and@ConfigurationsMichael PellatonNetcetera189
  2. 2. AGENDA> Spring @Configuration classes> An Annotation Processor for Validation> Unit Testing the Annotation Processor 2
  3. 3. Code ExamplesThe code in this presentation is simplified and doesn’t compile.Full length, compiling version of the code:http://github.com/pellaton/jazoon2012-talk 3
  4. 4. Spring @Configuration Classes> Java-based Spring application context configuration> An alternative to XML or annotation based configurations> Example: @Configuration public class ExampleConfiguration { @Bean public Example exampleBean() { return new ExampleImpl(); } } 4
  5. 5. Let’s Read the Javadoc… Must not Must have a visible be final no-arg constructor @Configuration Must not public class ExampleConfiguration { be Private ... @Bean public Example exampleBean() { return new ExampleImpl(); Must not } be final } ... Must not should be static if returning return void a BeanFactoryPostProcessor 5
  6. 6. What If There’s Something Wrong?Exception in thread "main" org...BeanDefinitionParsingException: Configuration problem: @Configuration class ExampleConfiguration may not be final. Remove the final modifier to continue. 6
  7. 7. Your Developers 7
  8. 8. Annotation Processors> Annotations can be processed at – Runtime  reflection (methods on Class, Method & Co) – Compile time  annotation processor> JSR-269 “Pluggable Annotation Processing API” – Introduced with Java 6 – Replaces “Annotation Processing Tool APT” of Java 5 8
  9. 9. JSR-269 Annotation Processors> A Java compiler plugin> An implementation of Processor> Interacts through ProcessingEnvironment injected in init() – Messenger to emit compiler messages – Filer to create classes and resources> Works with the Mirror (Model) API – Element represents a static Java language-level construct (class, package, method, …) – TypeMirror represents a Java type> process() is called in rounds to process an annotation on a type – Access to current compilation/processing state through RoundEnvironment – May claim an annotation: subsequent processors are not called 9
  10. 10. The Validating Annotation Processor@SupportedSourceVersion(SourceVersion.RELEASE_7)@SupportedAnnotationTypes(value = "org...Configuration")public class JazoonProcessor extends AbstractProcessor { private Elements elementUtils; private Messager messager; private TypeElement configurationTypeElement; public synchronized void init(ProcessingEnvironment env) { elementUtils = env.getElementUtils(); messager = env.getMessager(); configurationTypeElement = elementUtils.getTypeElement( "org.springframework...Configuration"); } 10
  11. 11. The Validating Annotation Processorpublic boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { if (!roundEnv.errorRaised() && !roundEnv.processingOver()) { for (TypeElement ann : annotations) { for (Element element : roundEnv.getElementsAnnotatedWith(ann)) { if (element instanceof TypeElement) { processElement((TypeElement) element); } } } } // don’t consume the annotation type return false;} 11
  12. 12. The Validating Annotation Processorprivate void processElement(TypeElement typeElement) { for (AnnotationMirror ann : typeElement.getAnnotationMirrors()) { Element annTypeElement = ann.getAnnotationType().asElement(); if (annTypeElement.equals(configurationTypeElement)) { if (typeElement.getModifiers().contains(Modifier.FINAL)) { messager.printMessage(Kind.ERROR, "@Configuration classes must not be final.", typeElement); } } }} 12
  13. 13. The Result 13
  14. 14. The Result$ mvn clean compile...[ERROR] Failed to execute goal ...: compileCompilation failure:[ERROR] /.../ExampleConfiguration.java:[7,13] error: @Configuration classes must not be final.[ERROR] /.../ExampleConfiguration.java:[10,16] error: @Bean methods must not be private. 14
  15. 15. Your Developer How about unit testing your code? 15
  16. 16. The Java Programming Language Compiler API> Idea: A unit test that compiles (faulty) classes and checks the compiler output produced by the annotation processor> JSR-199 The Java Programming Language Compiler API (Java 6)> Programmatic interface to the Java compiler> Requires a JDK 16
  17. 17. The Java Compiler API : Main Components> The JavaCompiler is the – interface to the Java compiler – Factory for CompilationTasks – Instance is obtained through ToolProvider> The CompilationTask is a future of a compilation task> Source and class files are read and written using the JavaFileManager> A message emitted during compilation is called a Diagnostic> Diagnostics are stored by the DiagnosticCollector 17
  18. 18. The Java Compiler API : Main Components ToolProvider creates JavaCompiler creates CompilationTask reads/writes emits listens java/class files holdsJavaFileManager Diagnostic DiagnosticCollector 18
  19. 19. Compiling Classes in Unit Tests for Processors/** Tests the detection of final @Configuration classes. */@Testpublic void finalConfigurationClass() throws IOException { List<Diagnostic> diagnostics = AnnotationProcessorTestCompiler.compileClass( "/com/github/pellaton/jazoon2012/FinalTestConfiguration.java", new JazoonProcessor()); DiagnosticsAssert.assertContainsSingleMessage(Kind.ERROR, 16, diagnostics);} 19
  20. 20. Compiling Classes in Unit Tests for Processorspublic static List<Diagnostic> compileClass(String clazzName, Processor processor) { DiagnosticCollector<> collector = new DiagnosticCollector<>(); JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); Locale locale = Locale.getDefault(); StandardJavaFileManager fileManager = compiler.getStandardFileManager(collector, locale, null); Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(classToCompile); // the infrastructure is now ready 20
  21. 21. Compiling Classes in Unit Tests for Processors // compile the class and return the result CompilationTask task = compiler.getTask(null, fileManager, collector, "-proc:only", null, compilationUnits); task.setProcessors(processor); task.call(); return collector.getDiagnostics();} 21
  22. 22. The Result 22
  23. 23. Conclusion> Annotation processors can be used to extend the tooling and build beyond the traditional purposes like code generation> To unit test an annotation processor, employ the Java compiler API> @Configuration and other annotation-based frameworks: try hard to find problems as early as possible 23
  24. 24. Michael Pellaton www.netcetera.comNetcetera michael.pellaton@netcetera.chExamples & Links: github.com/pellaton/jazoon2012-talk

×