Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Write Yourself an Annotation Processor

Ladislav Thon
February 07, 2015
20

Write Yourself an Annotation Processor

Annotation processors were standardized in Java 6, but it wasn't until recently that they began gaining some popularity. In this talk, I will argue that they are a pretty nice form of compile-time metaprogramming, a facility which a lot of languages are sorely lacking. I will explain why it makes sense to write an annotation processor, show some real-world examples, both small and big, and then implement a simple yet useful annotation processor from scratch.

Ladislav Thon

February 07, 2015
Tweet

Transcript

  1. Write Yourself an Annotation Processor ladicek@gmail.com

  2. None
  3. Write Yourself an Annotation Processor ladicek@gmail.com

  4. Why?

  5. First... What?

  6. None
  7. | | v .-------------. | Code | '-------------' | .-------------.

    | | Code | | | Generator | | '-------------' | | v | .-------------. '------>| Compiler | '-------------' | | Compiled v Code
  8. | | v .-------------. .------>| Code *.java | | '-------------'

    | | .-------------. | | Annotation | | | Processor | | '-------------' | ^ v | .-------------. '-------| Compiler | '-------------' | | Compiled v Code
  9. So... Why?

  10. None
  11. got a problem?

  12. We can solve any problem by introducing an extra level

    of indirection. fundamental theorem of software engineering
  13. compile-time metaprogramming

  14. None
  15. None
  16. None
  17. Examples

  18. google.github.io/auto Save time. Save code. Save sanity.

  19. @AutoService(Plugin.class) public class MyPlugin implements Plugin { ... }

  20. @AutoValue public abstract class Person { public static Person of(String

    name, int age) { return new AutoValue_Person(name, age); } public abstract String name(); public abstract int age(); }
  21. square.github.io/dagger javax.inject

  22. @Module class DripCoffeeModule { @Provides Heater provideHeater() { return new

    ElectricHeater(); } @Provides Pump providePump(Thermosiphon pump) { return pump; } }
  23. jakewharton.github.io/ butterknife view injection for Android

  24. public class ExampleActivity extends Activity { @InjectView(R.id.title) TextView title; @InjectView(R.id.subtitle)

    TextView subtitle; @InjectView(R.id.footer) TextView footer; @Override public void onCreate(Bundle state) { super.onCreate(state); setContentView(R.layout.simple_activity); ButterKnife.inject(this); ... use injected views ... } }
  25. JBoss Logging Tools logging internationalization

  26. @MessageLogger(projectCode = "EXMPL") public interface ExampleLogger { ExampleLogger LOGGER =

    Logger.getMessageLogger( ExampleLogger.class, "com.example"); @LogMessage(level = Level.INFO) @Message(id = 1, value = "Version: %s") void version(String version); @LogMessage(level = Level.FATAL) @Message(id = 2, value = "Too bad, %s is melting") void meltDown(@Cause Throwable cause, String value); }
  27. openjdk.java.net/projects/ code-tools/jmh Java Microbenchmark Harness

  28. @State(Scope.Thread) @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) public class JMHSample_08_DeadCode { private double x

    = Math.PI; @Benchmark public void wrong() { // the entire computation can be optimized out Math.log(x); } @Benchmark public double correct() { return Math.log(x); } }
  29. openjdk.java.net/projects/ code-tools/jcstress Java Concurrency Stress tests

  30. @JCStressTest @Outcome(id = "[0]", expect = Expect.ACCEPTABLE) @Outcome(id = "[-1]",

    expect = Expect.ACCEPTABLE) @Outcome( expect = Expect.ACCEPTABLE_SPEC) @State public class LongAtomicityTest { long x; @Actor public void actor1() { x = -1; } @Actor public void actor2(LongResult1 r) { r.r1 = x; } }
  31. etc. etc. etc. etc.

  32. I’m in! How?

  33. None
  34. | | v .-------------. .------>| Code *.java | | '-------------'

    | | .-------------. | | Annotation | | | Processor | | '-------------' | ^ v | .-------------. '-------| Compiler | '-------------' | | Compiled v Code
  35. Collecting data

  36. 1) Beware of exceptions Catch everything in process and print

    a stacktrace
  37. 2) Beware of class loading Don’t read Class-typed annotation values

  38. 3) Build a typed model

  39. 4) Tie errors to the elements

  40. 5) Don’t claim the annotations Unless it makes sense

  41. Generating code

  42. 1) Mustache (+ others) https://github.com/spullara/mustache.java

  43. 2) JavaPoet https://github.com/square/javapoet http://corner.squareup.com/2015/01/javapoet.html

  44. 3) JDeparser https://github.com/jdeparser/jdeparser2 http://dmlloyd.github.io/presentations/jdeparser

  45. Testing is possible https://github.com/google/compile-testing

  46. Resources https://www.youtube.com/watch?v=dOcs-NKK-RA http://jamezp.github.io/talks/annotation-processor

  47. Q’s? A’s http://devconf.cz/f/99