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

Write Yourself an Annotation Processor

Ladislav Thon
February 07, 2015
26

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. | | v .-------------. | Code | '-------------' | .-------------.

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

    | | .-------------. | | Annotation | | | Processor | | '-------------' | ^ v | .-------------. '-------| Compiler | '-------------' | | Compiled v Code
  3. We can solve any problem by introducing an extra level

    of indirection. fundamental theorem of software engineering
  4. @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(); }
  5. @Module class DripCoffeeModule { @Provides Heater provideHeater() { return new

    ElectricHeater(); } @Provides Pump providePump(Thermosiphon pump) { return pump; } }
  6. 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 ... } }
  7. @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); }
  8. @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); } }
  9. @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; } }
  10. | | v .-------------. .------>| Code *.java | | '-------------'

    | | .-------------. | | Annotation | | | Processor | | '-------------' | ^ v | .-------------. '-------| Compiler | '-------------' | | Compiled v Code