Annotation Processing Boilerplate Destruction (Square Waterloo 2014)

Annotation Processing Boilerplate Destruction (Square Waterloo 2014)

The Java programming language has a knack for requiring a lot of boilerplate code. Annotation processing is a feature of the Java compiler which provides hooks that allow automatic code generation based on annotations. This greatly simplifies your code by pushing the burden of the boilerplate on automated tooling.

This talk will briefly cover on showcasing existing annotation processors for Android development. We will then cover how to get started writing your own annotation processor.

Video: http://youtu.be/dOcs-NKK-RA

54879f243e5b72eedb2d379bed6fda27?s=128

Jake Wharton
PRO

September 23, 2014
Tweet

Transcript

  1. Annotation Processing Jake Wharton Boilerplate Destruction!

  2. Annotation Processing Jake Wharton Boilerplate Destruction!

  3. JSR 269

  4. JSR 269 • 6 months after Java 5 released

  5. JSR 269 • 6 months after Java 5 released •

    “Pluggable Annotation Processing API”
  6. JSR 269 • 6 months after Java 5 released •

    “Pluggable Annotation Processing API” • Preceded by doclet and apt standalone tools
  7. JSR 269 • 6 months after Java 5 released •

    “Pluggable Annotation Processing API” • Preceded by doclet and apt standalone tools • Google, Oracle, Sun, BEA Systems sponsored
  8. JSR 269 • 6 months after Java 5 released •

    “Pluggable Annotation Processing API” • Preceded by doclet and apt standalone tools • Google, Oracle, Sun, BEA Systems sponsored • Simplify and standardize processing annotations
  9. JSR 269 • 6 months after Java 5 released •

    “Pluggable Annotation Processing API” • Preceded by doclet and apt standalone tools • Google, Oracle, Sun, BEA Systems sponsored • Simplify and standardize processing annotations • No standalone tool, part of javac
  10. AutoValue @AutoValue
 abstract class Animal {
 static Animal create(String name,

    int numberOfLegs) {
 return new AutoValue_Animal(name, numberOfLegs);
 } 
 abstract String name();
 abstract int numberOfLegs();
 } github.com/google/auto/
  11. AutoValue github.com/google/auto/ final class AutoValue_Animal extends Animal {
 private final

    String name;
 private final int numberOfLegs;
 
 AutoValue_Animal(
 String name,
 int numberOfLegs) {
 if (name == null) {
 throw new NullPointerException("Null name");
 }
 this.name = name;
 this.numberOfLegs = numberOfLegs;
 }
 
 @Override
 String name() {
 return name;
 }
 
 @Override
 int numberOfLegs() {
 return numberOfLegs;
 }
 
 @Override
 public String toString() {
 return "Animal{"
 + "name=" + name
 + ", numberOfLegs=" + numberOfLegs
 + "}";
 }
 
 @Override
 public boolean equals(Object o) {
 if (o == this) {
 return true;
 }
 if (o instanceof Animal) {
 Animal that = (Animal) o;
 return (this.name.equals(that.name()))
 && (this.numberOfLegs == that.numberOfLegs());
 }
 return false;
 }
 
 @Override
 public int hashCode() {
 int h = 1;
 h *= 1000003;
 h ^= name.hashCode();
 h *= 1000003;
 h ^= numberOfLegs;
 return h;
 }
 }
  12. AutoValue github.com/google/auto/ final class AutoValue_Animal extends Animal {
 private final

    String name;
 private final int numberOfLegs;
 
 AutoValue_Animal(
 String name,
 int numberOfLegs) {
 if (name == null) {
 throw new NullPointerException("Null name");
 }
 this.name = name;
 this.numberOfLegs = numberOfLegs;
 }
 
 @Override
 String name() {
 return name;
 }
 
 @Override
 int numberOfLegs() {
 return numberOfLegs;
 }
 
 @Override
 public String toString() {
 return "Animal{"
 + "name=" + name
 + ", numberOfLegs=" + numberOfLegs
 + "}";
 }
 
 @Override
 public boolean equals(Object o) {
 if (o == this) {
 return true;
 }
 if (o instanceof Animal) {
 Animal that = (Animal) o;
 return (this.name.equals(that.name()))
 && (this.numberOfLegs == that.numberOfLegs());
 }
 return false;
 }
 
 @Override
 public int hashCode() {
 int h = 1;
 h *= 1000003;
 h ^= name.hashCode();
 h *= 1000003;
 h ^= numberOfLegs;
 return h;
 }
 } Final fields Constructor Getters .toString() .equals() .hashCode()
  13. AutoParcel github.com/frankiesardo/auto-parcel/ @AutoParcel
 abstract class Animal implements Parcelable {
 static

    Animal create(String name, int numberOfLegs) {
 return new AutoParcel_Animal(name, numberOfLegs);
 } 
 abstract String name();
 abstract int numberOfLegs();
 }
  14. AutoParcel github.com/frankiesardo/auto-parcel/ @AutoParcel
 abstract class Animal implements Parcelable {
 static

    Animal create(String name, int numberOfLegs) {
 return new AutoParcel_Animal(name, numberOfLegs);
 } 
 abstract String name();
 abstract int numberOfLegs();
 }
  15. AutoParcel final class AutoParcel_Animal extends Animal {
 private final String

    name;
 private final int numberOfLegs;
 
 AutoParcel_Animal(
 String name,
 int numberOfLegs) {
 if (name == null) {
 throw new NullPointerException("Null name");
 }
 this.name = name;
 this.numberOfLegs = numberOfLegs;
 }
 
 @Override
 String name() {
 return name;
 }
 
 @Override
 int numberOfLegs() {
 return numberOfLegs;
 }
 
 @Override
 public String toString() {
 return "Animal{"
 + "name=" + name
 + ", numberOfLegs=" + numberOfLegs
 + "}";
 }
 
 @Override
 public boolean equals(Object o) {
 if (o == this) {
 return true;
 }
 if (o instanceof Animal) {
 Animal that = (Animal) o;
 return (this.name.equals(that.name()))
 && (this.numberOfLegs == that.numberOfLegs());
 }
 return false;
 }
 
 @Override
 public int hashCode() {
 int h = 1;
 h *= 1000003;
 h ^= name.hashCode();
 h *= 1000003;
 h ^= numberOfLegs;
 return h;
 }
 
 public static final Parcelable.Creator<Animal> CREATOR = new Parcelable.Creator<Animal>() {
 @Override public Animal createFromParcel(Parcel in) {
 return new AutoParcel_Animal(in);
 }
 @Override public Animal[] newArray(int size) {
 return new Animal[size];
 }
 };
 
 private final static ClassLoader CL = AutoParcel_Animal.class.getClassLoader();
 
 private AutoParcel_Animal(Parcel in) {
 this(
 (String) in.readValue(CL),
 (Integer) in.readValue(CL));
 }
 
 @Override public void writeToParcel(Parcel dest, int flags) {
 dest.writeValue(name);
 dest.writeValue(numberOfLegs);
 }
 
 @Override public int describeContents() {
 return 0;
 }
 } github.com/frankiesardo/auto-parcel/
  16. AutoParcel final class AutoParcel_Animal extends Animal {
 private final String

    name;
 private final int numberOfLegs;
 
 AutoParcel_Animal(
 String name,
 int numberOfLegs) {
 if (name == null) {
 throw new NullPointerException("Null name");
 }
 this.name = name;
 this.numberOfLegs = numberOfLegs;
 }
 
 @Override
 String name() {
 return name;
 }
 
 @Override
 int numberOfLegs() {
 return numberOfLegs;
 }
 
 @Override
 public String toString() {
 return "Animal{"
 + "name=" + name
 + ", numberOfLegs=" + numberOfLegs
 + "}";
 }
 
 @Override
 public boolean equals(Object o) {
 if (o == this) {
 return true;
 }
 if (o instanceof Animal) {
 Animal that = (Animal) o;
 return (this.name.equals(that.name()))
 && (this.numberOfLegs == that.numberOfLegs());
 }
 return false;
 }
 
 @Override
 public int hashCode() {
 int h = 1;
 h *= 1000003;
 h ^= name.hashCode();
 h *= 1000003;
 h ^= numberOfLegs;
 return h;
 }
 
 public static final Parcelable.Creator<Animal> CREATOR = new Parcelable.Creator<Animal>() {
 @Override public Animal createFromParcel(Parcel in) {
 return new AutoParcel_Animal(in);
 }
 @Override public Animal[] newArray(int size) {
 return new Animal[size];
 }
 };
 
 private final static ClassLoader CL = AutoParcel_Animal.class.getClassLoader();
 
 private AutoParcel_Animal(Parcel in) {
 this(
 (String) in.readValue(CL),
 (Integer) in.readValue(CL));
 }
 
 @Override public void writeToParcel(Parcel dest, int flags) {
 dest.writeValue(name);
 dest.writeValue(numberOfLegs);
 }
 
 @Override public int describeContents() {
 return 0;
 }
 } Final fields Constructor Getters .toString() .equals() .hashCode() github.com/frankiesardo/auto-parcel/ CREATOR Parcel constructor Parcel writer
  17. Butter Knife class SimpleActivity extends Activity {
 @InjectView(R.id.title) TextView title;


    @InjectView(R.id.hello) Button hello;
 @InjectView(R.id.list_of_things) ListView listOfThings;
 @OnClick(R.id.hello) void sayHello() {
 Toast.makeText(this, "Hello, views!", LENGTH_SHORT).show();
 } ! 
 // ...
 } jakewharton.github.io/butterknife/
  18. Butter Knife jakewharton.github.io/butterknife/ static void inject(Finder finder, final SimpleActivity target,

    Object source) {
 View view;
 view = finder.findRequired(source, 2130968576, "field 'title'");
 target.title = (android.widget.TextView) view;
 view = finder.findRequired(source, 2130968578, "field 'hello' and method 'sayHello'");
 target.hello = (android.widget.Button) view;
 view.setOnClickListener(new View.OnClickListener() {
 @Override public void onClick(View p0) {
 target.sayHello();
 }
 });
 view = finder.findRequired(source, 2130968579, "field 'listOfThings'"); target.listOfThings = (android.widget.ListView) view;
 }
  19. Butter Knife jakewharton.github.io/butterknife/ static void inject(Finder finder, final SimpleActivity target,

    Object source) {
 View view;
 view = finder.findRequired(source, 2130968576, "field 'title'");
 target.title = (android.widget.TextView) view;
 view = finder.findRequired(source, 2130968578, "field 'hello' and method 'sayHello'");
 target.hello = (android.widget.Button) view;
 view.setOnClickListener(new View.OnClickListener() {
 @Override public void onClick(View p0) {
 target.sayHello();
 }
 });
 view = finder.findRequired(source, 2130968579, "field 'listOfThings'"); target.listOfThings = (android.widget.ListView) view;
 }
  20. Butter Knife jakewharton.github.io/butterknife/ static void inject(Finder finder, final SimpleActivity target,

    Object source) {
 View view;
 view = finder.findRequired(source, 2130968576, "field 'title'");
 target.title = (android.widget.TextView) view;
 view = finder.findRequired(source, 2130968578, "field 'hello' and method 'sayHello'");
 target.hello = (android.widget.Button) view;
 view.setOnClickListener(new View.OnClickListener() {
 @Override public void onClick(View p0) {
 target.sayHello();
 }
 });
 view = finder.findRequired(source, 2130968579, "field 'listOfThings'"); target.listOfThings = (android.widget.ListView) view;
 }
  21. Butter Knife jakewharton.github.io/butterknife/ static void inject(Finder finder, final SimpleActivity target,

    Object source) {
 View view;
 view = finder.findRequired(source, 2130968576, "field 'title'");
 target.title = (android.widget.TextView) view;
 view = finder.findRequired(source, 2130968578, "field 'hello' and method 'sayHello'");
 target.hello = (android.widget.Button) view;
 view.setOnClickListener(new View.OnClickListener() {
 @Override public void onClick(View p0) {
 target.sayHello();
 }
 });
 view = finder.findRequired(source, 2130968579, "field 'listOfThings'"); target.listOfThings = (android.widget.ListView) view;
 }
  22. Dagger square.github.io/dagger/ @Module(injects = CoffeeApp.class)
 class DripCoffeeModule {
 @Provides @Singleton

    Heater provideHeater() {
 return new ElectricHeater();
 }
 
 @Provides Pump providePump(Thermosiphon pump) {
 return pump;
 }
 }

  23. Dagger class CoffeeMaker {
 @Inject Lazy<Heater> heater;
 @Inject Pump pump;


    
 public void brew() {
 heater.get().on();
 pump.pump();
 System.out.println(" [_]P coffee! [_]P ");
 heater.get().off();
 }
 }
 square.github.io/dagger/
  24. Dagger square.github.io/dagger/ class DripCoffeeModule$$ModuleAdapter extends ModuleAdapter<DripCoffeeModule> { 
 @Override
 public

    void getBindings(BindingsGroup bindings, DripCoffeeModule module) {
 bindings.contributeProvidesBinding("coffee.Heater", new ProvideHeaterAdapter(module)); bindings.contributeProvidesBinding("coffee.Pump",
 new ProvidePumpAdapter(module));
 } }
  25. Dagger square.github.io/dagger/ class DripCoffeeModule$$ModuleAdapter extends ModuleAdapter<DripCoffeeModule> { 
 @Override
 public

    void getBindings(BindingsGroup bindings, DripCoffeeModule module) {
 bindings.contributeProvidesBinding("coffee.Heater", new ProvideHeaterAdapter(module)); bindings.contributeProvidesBinding("coffee.Pump",
 new ProvidePumpAdapter(module));
 } }
  26. Dagger square.github.io/dagger/ class ProvideHeaterProvidesAdapter extends ProvidesBinding<Heater> { 
 private final

    DripCoffeeModule module;
 
 public ProvideHeaterProvidesAdapter(DripCoffeeModule module) {
 this.module = module;
 }
 
 @Override
 public Heater get() {
 return module.provideHeater();
 }
 }
  27. Dagger square.github.io/dagger/ class CoffeeMaker$$InjectAdapter
 extends Binding<CoffeeMaker> {
 
 private Binding<Lazy<Heater>>

    heater;
 private Binding<Pump> pump;
 
 CoffeeMaker$$InjectAdapter() {
 super("coffee.CoffeeMaker", CoffeeMaker.class);
 }
 
 @Override public void attach(Linker linker) {
 heater = linker.requestBinding("dagger.Lazy<coffee.Heater>");
 pump = linker.requestBinding("coffee.Pump");
 } ! // ...
 }
  28. Dagger square.github.io/dagger/ class CoffeeMaker$$InjectAdapter
 extends Binding<CoffeeMaker> {
 
 private Binding<Lazy<Heater>>

    heater;
 private Binding<Pump> pump;
 
 CoffeeMaker$$InjectAdapter() {
 super("coffee.CoffeeMaker", CoffeeMaker.class);
 }
 
 @Override public void attach(Linker linker) {
 heater = linker.requestBinding("dagger.Lazy<coffee.Heater>");
 pump = linker.requestBinding("coffee.Pump");
 } ! // ...
 }
  29. Dagger square.github.io/dagger/ class CoffeeMaker$$InjectAdapter
 extends Binding<CoffeeMaker> {
 
 // ...


    
 @Override public CoffeeMaker get() {
 CoffeeMaker result = new CoffeeMaker();
 injectMembers(result);
 return result;
 }
 
 @Override public void injectMembers(CoffeeMaker object) {
 object.heater = heater.get();
 object.pump = pump.get();
 }
 }
  30. Dagger square.github.io/dagger/ class CoffeeMaker$$InjectAdapter
 extends Binding<CoffeeMaker> {
 
 // ...


    
 @Override public CoffeeMaker get() {
 CoffeeMaker result = new CoffeeMaker();
 injectMembers(result);
 return result;
 }
 
 @Override public void injectMembers(CoffeeMaker object) {
 object.heater = heater.get();
 object.pump = pump.get();
 }
 }
  31. Dagger square.github.io/dagger/ @Module(injects = CoffeeApp.class)
 class DripCoffeeModule {
 @Provides @Singleton

    Heater provideHeater() {
 return new ElectricHeater();
 }
 
 @Provides Pump providePump(Thermosiphon pump) {
 return pump;
 }
 } class CoffeeMaker {
 @Inject Lazy<Heater> heater;
 @Inject Pump pump;
 // ...
 }
  32. Dagger square.github.io/dagger/ @Module(injects = CoffeeApp.class)
 class DripCoffeeModule {
 @Provides @Singleton

    Heater provideHeater() {
 return new ElectricHeater();
 }
 
 @Provides Pump providePump(Thermosiphon pump) {
 return pump;
 }
 } class CoffeeMaker {
 @Inject Lazy<Heater> heater;
 @Inject Pump pump;
 // ...
 } class ProvideHeaterProvidesAdapter extends ProvidesBinding<Heater> { 
 private final DripCoffeeModule module;
 
 public ProvideHeaterProvidesAdapter(DripCoffeeModule module) {
 this.module = module;
 }
 
 @Override
 public Heater get() {
 return module.provideHeater();
 }
 }
  33. Dagger square.github.io/dagger/ @Module(injects = CoffeeApp.class)
 class DripCoffeeModule {
 @Provides @Singleton

    Heater provideHeater() {
 return new ElectricHeater();
 }
 
 @Provides Pump providePump(Thermosiphon pump) {
 return pump;
 }
 } class CoffeeMaker {
 @Inject Lazy<Heater> heater;
 @Inject Pump pump;
 // ...
 } class DripCoffeeModule$$ModuleAdapter extends ModuleAdapter<DripCoffeeModule> { 
 @Override
 public void getBindings(BindingsGroup bindings, DripCoffeeModule module) {
 bindings.contributeProvidesBinding("coffee.Heater", new ProvideHeaterAdapter(module)); bindings.contributeProvidesBinding("coffee.Pump",
 new ProvidePumpAdapter(module));
 } } class ProvideHeaterProvidesAdapter extends ProvidesBinding<Heater> { 
 private final DripCoffeeModule module;
 
 public ProvideHeaterProvidesAdapter(DripCoffeeModule module) {
 this.module = module;
 }
 
 @Override
 public Heater get() {
 return module.provideHeater();
 }
 }
  34. Dagger square.github.io/dagger/ @Module(injects = CoffeeApp.class)
 class DripCoffeeModule {
 @Provides @Singleton

    Heater provideHeater() {
 return new ElectricHeater();
 }
 
 @Provides Pump providePump(Thermosiphon pump) {
 return pump;
 }
 } class CoffeeMaker {
 @Inject Lazy<Heater> heater;
 @Inject Pump pump;
 // ...
 } class DripCoffeeModule$$ModuleAdapter extends ModuleAdapter<DripCoffeeModule> { 
 @Override
 public void getBindings(BindingsGroup bindings, DripCoffeeModule module) {
 bindings.contributeProvidesBinding("coffee.Heater", new ProvideHeaterAdapter(module)); bindings.contributeProvidesBinding("coffee.Pump",
 new ProvidePumpAdapter(module));
 } } class ProvideHeaterProvidesAdapter extends ProvidesBinding<Heater> { 
 private final DripCoffeeModule module;
 
 public ProvideHeaterProvidesAdapter(DripCoffeeModule module) {
 this.module = module;
 }
 
 @Override
 public Heater get() {
 return module.provideHeater();
 }
 } class ObjectGraph {
 // ...
 }
  35. Dagger square.github.io/dagger/ @Module(injects = CoffeeApp.class)
 class DripCoffeeModule {
 @Provides @Singleton

    Heater provideHeater() {
 return new ElectricHeater();
 }
 
 @Provides Pump providePump(Thermosiphon pump) {
 return pump;
 }
 } class CoffeeMaker {
 @Inject Lazy<Heater> heater;
 @Inject Pump pump;
 // ...
 } class DripCoffeeModule$$ModuleAdapter extends ModuleAdapter<DripCoffeeModule> { 
 @Override
 public void getBindings(BindingsGroup bindings, DripCoffeeModule module) {
 bindings.contributeProvidesBinding("coffee.Heater", new ProvideHeaterAdapter(module)); bindings.contributeProvidesBinding("coffee.Pump",
 new ProvidePumpAdapter(module));
 } } class ProvideHeaterProvidesAdapter extends ProvidesBinding<Heater> { 
 private final DripCoffeeModule module;
 
 public ProvideHeaterProvidesAdapter(DripCoffeeModule module) {
 this.module = module;
 }
 
 @Override
 public Heater get() {
 return module.provideHeater();
 }
 } class CoffeeMaker$$InjectAdapter
 extends Binding<CoffeeMaker> {
 
 @Override public void attach(Linker linker) {
 heater = linker.requestBinding("dagger.Lazy<coffee.Heater>");
 pump = linker.requestBinding("coffee.Pump");
 } 
 @Override public void injectMembers(CoffeeMaker object) {
 object.heater = heater.get();
 object.pump = pump.get();
 } ! // ...
 } class ObjectGraph {
 // ...
 }
  36. Dagger square.github.io/dagger/ @Module(injects = CoffeeApp.class)
 class DripCoffeeModule {
 @Provides @Singleton

    Heater provideHeater() {
 return new ElectricHeater();
 }
 
 @Provides Pump providePump(Thermosiphon pump) {
 return pump;
 }
 } class CoffeeMaker {
 @Inject Lazy<Heater> heater;
 @Inject Pump pump;
 // ...
 } class DripCoffeeModule$$ModuleAdapter extends ModuleAdapter<DripCoffeeModule> { 
 @Override
 public void getBindings(BindingsGroup bindings, DripCoffeeModule module) {
 bindings.contributeProvidesBinding("coffee.Heater", new ProvideHeaterAdapter(module)); bindings.contributeProvidesBinding("coffee.Pump",
 new ProvidePumpAdapter(module));
 } } class ProvideHeaterProvidesAdapter extends ProvidesBinding<Heater> { 
 private final DripCoffeeModule module;
 
 public ProvideHeaterProvidesAdapter(DripCoffeeModule module) {
 this.module = module;
 }
 
 @Override
 public Heater get() {
 return module.provideHeater();
 }
 } class CoffeeMaker$$InjectAdapter
 extends Binding<CoffeeMaker> {
 
 @Override public void attach(Linker linker) {
 heater = linker.requestBinding("dagger.Lazy<coffee.Heater>");
 pump = linker.requestBinding("coffee.Pump");
 } 
 @Override public void injectMembers(CoffeeMaker object) {
 object.heater = heater.get();
 object.pump = pump.get();
 } ! // ...
 } class ObjectGraph {
 // ...
 }
  37. Dagger square.github.io/dagger/ @Module(injects = CoffeeApp.class)
 class DripCoffeeModule {
 @Provides @Singleton

    Heater provideHeater() {
 return new ElectricHeater();
 }
 
 @Provides Pump providePump(Thermosiphon pump) {
 return pump;
 }
 } class CoffeeMaker {
 @Inject Lazy<Heater> heater;
 @Inject Pump pump;
 // ...
 } class DripCoffeeModule$$ModuleAdapter extends ModuleAdapter<DripCoffeeModule> { 
 @Override
 public void getBindings(BindingsGroup bindings, DripCoffeeModule module) {
 bindings.contributeProvidesBinding("coffee.Heater", new ProvideHeaterAdapter(module)); bindings.contributeProvidesBinding("coffee.Pump",
 new ProvidePumpAdapter(module));
 } } class ProvideHeaterProvidesAdapter extends ProvidesBinding<Heater> { 
 private final DripCoffeeModule module;
 
 public ProvideHeaterProvidesAdapter(DripCoffeeModule module) {
 this.module = module;
 }
 
 @Override
 public Heater get() {
 return module.provideHeater();
 }
 } class CoffeeMaker$$InjectAdapter
 extends Binding<CoffeeMaker> {
 
 @Override public void attach(Linker linker) {
 heater = linker.requestBinding("dagger.Lazy<coffee.Heater>");
 pump = linker.requestBinding("coffee.Pump");
 } 
 @Override public void injectMembers(CoffeeMaker object) {
 object.heater = heater.get();
 object.pump = pump.get();
 } ! // ...
 }
  38. Schematic interface NoteColumns {
 
 @DataType(INTEGER) @PrimaryKey @AutoIncrement
 String _ID

    = "_id";
 
 @DataType(INTEGER) @References(table = NotesDatabase.LISTS,
 column = ListColumns._ID)
 String LIST_ID = "listId";
 
 @DataType(TEXT) String NOTE = "note";
 } github.com/SimonVT/schematic/
  39. Schematic @Database(version = NotesDatabase.VERSION)
 public final class NotesDatabase {
 


    public static final int VERSION = 1;
 
 @Table(ListColumns.class)
 public static final String LISTS = "lists";
 
 @Table(NoteColumns.class)
 public static final String NOTES = "notes";
 
 } github.com/SimonVT/schematic/
  40. Schematic @ContentProvider(authority = NotesProvider.AUTHORITY,
 database = NotesDatabase.class)
 public final class

    NotesProvider {
 // ...
 } github.com/SimonVT/schematic/
  41. Execution

  42. Execution • Happens automatically when javac runs.

  43. Execution • Happens automatically when javac runs. • ServiceLoader finds

    and creates Processor instances.
  44. interface Processor {
 Set<String> getSupportedOptions();
 
 Set<String> getSupportedAnnotationTypes();
 
 SourceVersion

    getSupportedSourceVersion();
 
 void init(ProcessingEnvironment processingEnv);
 
 boolean process(Set<? extends TypeElement> annotations,
 RoundEnvironment roundEnv);
 
 Iterable<? extends Completion> getCompletions(Element element,
 AnnotationMirror annotation,
 ExecutableElement member,
 String userText);
 }
  45. public class ExampleProcessor extends AbstractProcessor {
 
 
 
 


    
 
 
 
 
 
 
 
 
 }
  46. public class ExampleProcessor extends AbstractProcessor {
 @Override public SourceVersion getSupportedSourceVersion()

    {
 
 }
 
 
 
 
 
 
 
 
 
 
 }
  47. public class ExampleProcessor extends AbstractProcessor {
 @Override public SourceVersion getSupportedSourceVersion()

    {
 return SourceVersion.latestSupported();
 }
 
 
 
 
 
 
 
 
 
 
 }
  48. public class ExampleProcessor extends AbstractProcessor {
 @Override public SourceVersion getSupportedSourceVersion()

    {
 return SourceVersion.latestSupported();
 }
 
 @Override public Set<String> getSupportedAnnotationTypes() {
 
 }
 
 
 
 
 
 
 }
  49. public class ExampleProcessor extends AbstractProcessor {
 @Override public SourceVersion getSupportedSourceVersion()

    {
 return SourceVersion.latestSupported();
 }
 
 @Override public Set<String> getSupportedAnnotationTypes() {
 return Collections.singleton(Example.class.getName());
 }
 
 
 
 
 
 
 }
  50. public class ExampleProcessor extends AbstractProcessor {
 @Override public SourceVersion getSupportedSourceVersion()

    {
 return SourceVersion.latestSupported();
 }
 
 @Override public Set<String> getSupportedAnnotationTypes() {
 return Collections.singleton(Example.class.getName());
 }
 
 @Override public boolean process(
 Set<? extends TypeElement> annotations,
 RoundEnvironment env) {
 
 }
 }
  51. public class ExampleProcessor extends AbstractProcessor {
 // ...
 @Override public

    boolean process(
 Set<? extends TypeElement> annotations,
 RoundEnvironment env) {
 ! ! ! ! ! 
 }
 }
  52. public class ExampleProcessor extends AbstractProcessor {
 // ...
 
 @Override

    public boolean process(
 Set<? extends TypeElement> annotations,
 RoundEnvironment env) {
 Set<? extends Element> elements
 = env.getElementsAnnotatedWith(Example.class);
 
 
 
 
 
 }
 }
  53. public class ExampleProcessor extends AbstractProcessor {
 // ...
 
 @Override

    public boolean process(
 Set<? extends TypeElement> annotations,
 RoundEnvironment env) {
 Set<? extends Element> elements
 = env.getElementsAnnotatedWith(Example.class);
 for (Element element : elements) {
 System.out.println(element);
 }
 
 
 }
 }
  54. public class ExampleProcessor extends AbstractProcessor {
 // ...
 
 @Override

    public boolean process(
 Set<? extends TypeElement> annotations,
 RoundEnvironment env) {
 Set<? extends Element> elements
 = env.getElementsAnnotatedWith(Example.class);
 for (Element element : elements) {
 System.out.println(element);
 }
 
 return false;
 }
 }
  55. public class ExampleProcessor extends AbstractProcessor {
 @Override public SourceVersion getSupportedSourceVersion()

    {
 return SourceVersion.latestSupported();
 }
 
 @Override public Set<String> getSupportedAnnotationTypes() {
 return Collections.singleton(Example.class.getName());
 }
 
 @Override public boolean process(
 Set<? extends TypeElement> annotations,
 RoundEnvironment env) {
 Set<? extends Element> elements
 = env.getElementsAnnotatedWith(Example.class);
 for (Element element : elements) {
 System.out.println(element);
 }
 return false;
 }
 }
  56. Execution • Happens automatically when javac runs. • ServiceLoader finds

    and creates Processor instances.
  57. Execution • Happens automatically when javac runs. • ServiceLoader finds

    and creates Processor instances. • Inside a full JVM.
  58. Execution • Happens automatically when javac runs. • ServiceLoader finds

    and creates Processor instances. • Inside a full JVM. • Compiled sources and its dependencies not available.
  59. Execution • Happens automatically when javac runs. • ServiceLoader finds

    and creates Processor instances. • Inside a full JVM. • Compiled sources and its dependencies not available. • Bring your own dependencies.
  60. Environment interface Processor {
 Set<String> getSupportedOptions();
 
 Set<String> getSupportedAnnotationTypes();
 


    SourceVersion getSupportedSourceVersion();
 
 void init(ProcessingEnvironment processingEnv);
 
 boolean process(Set<? extends TypeElement> annotations,
 RoundEnvironment roundEnv);
 
 Iterable<? extends Completion> getCompletions(Element element,
 AnnotationMirror annotation,
 ExecutableElement member,
 String userText);
 }
  61. Environment interface Processor {
 Set<String> getSupportedOptions();
 
 Set<String> getSupportedAnnotationTypes();
 


    SourceVersion getSupportedSourceVersion();
 
 void init(ProcessingEnvironment processingEnv);
 
 boolean process(Set<? extends TypeElement> annotations,
 RoundEnvironment roundEnv);
 
 Iterable<? extends Completion> getCompletions(Element element,
 AnnotationMirror annotation,
 ExecutableElement member,
 String userText);
 }
  62. Environment interface Processor {
 Set<String> getSupportedOptions();
 
 Set<String> getSupportedAnnotationTypes();
 


    SourceVersion getSupportedSourceVersion();
 
 void init(ProcessingEnvironment processingEnv);
 
 boolean process(Set<? extends TypeElement> annotations,
 RoundEnvironment roundEnv);
 
 Iterable<? extends Completion> getCompletions(Element element,
 AnnotationMirror annotation,
 ExecutableElement member,
 String userText);
 }
  63. Processing Environment interface ProcessingEnvironment {
 Map<String, String> getOptions(); 
 SourceVersion

    getSourceVersion();
 
 Locale getLocale();
 
 Messager getMessager();
 
 Filer getFiler();
 
 Elements getElementUtils();
 
 Types getTypeUtils();
 }
  64. Processing Environment interface ProcessingEnvironment {
 Map<String, String> getOptions(); 
 SourceVersion

    getSourceVersion();
 
 Locale getLocale();
 
 Messager getMessager();
 
 Filer getFiler();
 
 Elements getElementUtils();
 
 Types getTypeUtils();
 }
  65. Processing Environment interface ProcessingEnvironment {
 Map<String, String> getOptions(); 
 SourceVersion

    getSourceVersion();
 
 Locale getLocale();
 
 Messager getMessager();
 
 Filer getFiler();
 
 Elements getElementUtils();
 
 Types getTypeUtils();
 }
  66. Processing Environment interface ProcessingEnvironment {
 Map<String, String> getOptions(); 
 SourceVersion

    getSourceVersion();
 
 Locale getLocale();
 
 Messager getMessager();
 
 Filer getFiler();
 
 Elements getElementUtils();
 
 Types getTypeUtils();
 }
  67. Elements @Example
 public class ExampleClass implements Runnable { 
 private

    final String name;
 
 public ExampleClass(String name) {
 this.name = name;
 }
 
 @Override public void run() {
 System.out.println("Hello, " + name);
 }
 }
  68. Elements @Example
 public class ExampleClass implements Runnable { 
 private

    final String name;
 
 public ExampleClass(String name) {
 this.name = name;
 }
 
 @Override public void run() {
 System.out.println("Hello, " + name);
 }
 } TypeElement
  69. Elements @Example
 public class ExampleClass implements Runnable { 
 private

    final String name;
 
 public ExampleClass(String name) {
 this.name = name;
 }
 
 @Override public void run() {
 System.out.println("Hello, " + name);
 }
 } TypeElement VariableElement
  70. Elements @Example
 public class ExampleClass implements Runnable { 
 private

    final String name;
 
 public ExampleClass(String name) {
 this.name = name;
 }
 
 @Override public void run() {
 System.out.println("Hello, " + name);
 }
 } TypeElement VariableElement ExecutableElement
  71. Elements @Example
 public class ExampleClass implements Runnable { 
 private

    final String name;
 
 public ExampleClass(String name) {
 this.name = name;
 }
 
 @Override public void run() {
 System.out.println("Hello, " + name);
 }
 } TypeElement VariableElement ExecutableElement ExecutableElement
  72. Elements @Example
 public class ExampleClass implements Runnable { 
 private

    final String name;
 
 public ExampleClass(String name) {
 this.name = name;
 }
 
 @Override public void run() {
 System.out.println("Hello, " + name);
 }
 } TypeElement VariableElement ExecutableElement ExecutableElement
  73. Elements @Example
 public class ExampleClass implements Runnable { 
 private

    final String name;
 
 public ExampleClass(String name) {
 this.name = name;
 }
 
 @Override public void run() {
 System.out.println("Hello, " + name);
 }
 } TypeElement VariableElement ExecutableElement ExecutableElement
  74. Types @Example
 public class ExampleClass implements Runnable { 
 private

    final String name;
 
 public ExampleClass(String name) {
 this.name = name;
 }
 
 @Override public void run() {
 System.out.println("Hello, " + name);
 }
 }
  75. Types @Example
 public class ExampleClass implements Runnable { 
 private

    final String name;
 
 public ExampleClass(String name) {
 this.name = name;
 }
 
 @Override public void run() {
 System.out.println("Hello, " + name);
 }
 }
  76. Types @Example
 public class ExampleClass implements Runnable { 
 private

    final String name;
 
 public ExampleClass(String name) {
 this.name = name;
 }
 
 @Override public void run() {
 System.out.println("Hello, " + name);
 }
 }
  77. Types @Example
 public class ExampleClass implements Runnable { 
 private

    final String name;
 
 public ExampleClass(String name) {
 this.name = name;
 }
 
 @Override public void run() {
 System.out.println("Hello, " + name);
 }
 }
  78. Types @Example
 public class ExampleClass implements Runnable { 
 private

    final String name;
 
 public ExampleClass(String name) {
 this.name = name;
 }
 
 @Override public void run() {
 System.out.println("Hello, " + name);
 }
 }
  79. Types @Example
 public class ExampleClass implements Runnable { 
 private

    final String name;
 
 public ExampleClass(String name) {
 this.name = name;
 }
 
 @Override public void run() {
 System.out.println("Hello, " + name);
 }
 }
  80. Environment public class ExampleProcessor extends AbstractProcessor {
 // ...
 


    @Override public boolean process(
 Set<? extends TypeElement> annotations,
 RoundEnvironment env) {
 Set<? extends Element> elements
 = env.getElementsAnnotatedWith(Example.class);
 for (Element element : elements) {
 System.out.println(element
 }
 return false;
 }
 } 
 
 
 
 
 
 
 
 
 );
 
 
 

  81. Environment public class ExampleProcessor extends AbstractProcessor {
 // ...
 


    @Override public boolean process(
 Set<? extends TypeElement> annotations,
 RoundEnvironment env) {
 Set<? extends Element> elements
 = env.getElementsAnnotatedWith(Example.class);
 for (Element element : elements) {
 System.out.println(element
 }
 return false;
 }
 } 
 
 
 
 
 
 
 
 
 );
 
 
 

  82. Environment public class ExampleProcessor extends AbstractProcessor {
 // ...
 


    @Override public boolean process(
 Set<? extends TypeElement> annotations,
 RoundEnvironment env) {
 Set<? extends Element> elements
 = env.getElementsAnnotatedWith(Example.class);
 for (Element element : elements) {
 System.out.println( );
 }
 return false;
 }
 } 
 
 
 
 
 
 
 
 
 element.asType()
 
 
 

  83. Environment public class ExampleProcessor extends AbstractProcessor {
 // ...
 


    @Override public boolean process(
 Set<? extends TypeElement> annotations,
 RoundEnvironment env) {
 Set<? extends Element> elements
 = env.getElementsAnnotatedWith(Example.class);
 for (Element element : elements) {
 System.out.println(element.asType());
 }
 return false;
 }
 }
  84. Environment public class ExampleProcessor extends AbstractProcessor {
 // ...
 


    @Override public boolean process(
 Set<? extends TypeElement> annotations,
 RoundEnvironment env) {
 Set<? extends Element> elements
 = env.getElementsAnnotatedWith(Example.class);
 for (Element element : elements) {
 System.out.println(element.asType());
 }
 return false;
 }
 }
  85. Environment public class ExampleProcessor extends AbstractProcessor {
 // ...
 


    @Override public boolean process(
 Set<? extends TypeElement> annotations,
 RoundEnvironment env) {
 Set<? extends Element> elements
 = env.getElementsAnnotatedWith(Example.class);
 for (Element element : elements) {
 System.out.println(element.asType());
 }
 return false;
 }
 }
  86. Processing Rounds @Example
 public class RandomClass {
 // ...
 }

  87. Processing Rounds @Example
 public class RandomClass {
 // ...
 }

    javac
  88. Processing Rounds @Example
 public class RandomClass {
 // ...
 }

    ExampleProcessor OtherProcessor javac
  89. Processing Rounds @Example
 public class RandomClass {
 // ...
 }

    ExampleProcessor OtherProcessor javac javac
  90. Processing Rounds @Example
 public class RandomClass {
 // ...
 }

    ExampleProcessor OtherProcessor javac RandomClass.class out/ @Example
 public class RandomClass {
 // ...
 } javac
  91. Processing Rounds @Example
 public class RandomClass {
 // ...
 }

    ExampleProcessor OtherProcessor javac RandomClass.class out/ @Example
 public class RandomClass {
 // ...
 } javac ExampleProcessor
  92. Processing Rounds @Example
 public class RandomClass {
 // ...
 }

    ExampleProcessor OtherProcessor javac RandomClass.class out/ @Other
 public class GeneratedClass {
 // ...
 } @Example
 public class RandomClass {
 // ...
 } javac ExampleProcessor
  93. Processing Rounds @Example
 public class RandomClass {
 // ...
 }

    ExampleProcessor OtherProcessor javac RandomClass.class out/ @Other
 public class GeneratedClass {
 // ...
 } @Example
 public class RandomClass {
 // ...
 } javac OtherProcessor
  94. Processing Rounds @Example
 public class RandomClass {
 // ...
 }

    ExampleProcessor OtherProcessor javac RandomClass.class out/ @Other
 public class GeneratedClass {
 // ...
 } @Example
 public class RandomClass {
 // ...
 } javac
  95. Processing Rounds @Example
 public class RandomClass {
 // ...
 }

    ExampleProcessor OtherProcessor javac RandomClass.class out/ @Other
 public class GeneratedClass {
 // ...
 } @Example
 public class RandomClass {
 // ...
 } javac
  96. Processing Rounds @Example
 public class RandomClass {
 // ...
 }

    ExampleProcessor OtherProcessor javac RandomClass.class out/ @Other
 public class GeneratedClass {
 // ...
 } @Example
 public class RandomClass {
 // ...
 }
  97. Processing Rounds @Example
 public class RandomClass {
 // ...
 }

    ExampleProcessor OtherProcessor javac RandomClass.class out/ @Other
 public class GeneratedClass {
 // ...
 } @Example
 public class RandomClass {
 // ...
 } javac
  98. Processing Rounds @Example
 public class RandomClass {
 // ...
 }

    ExampleProcessor OtherProcessor javac RandomClass.class out/ @Other
 public class GeneratedClass {
 // ...
 } @Example
 public class RandomClass {
 // ...
 } javac
  99. Processing Rounds @Example
 public class RandomClass {
 // ...
 }

    ExampleProcessor OtherProcessor javac RandomClass.class out/ @Other
 public class GeneratedClass {
 // ...
 } GeneratedClass.class @Example
 public class RandomClass {
 // ...
 } @Other
 public class GeneratedClass {
 // ...
 } javac
  100. Processing Rounds @Example
 public class RandomClass {
 // ...
 }

    ExampleProcessor OtherProcessor javac RandomClass.class out/ @Other
 public class GeneratedClass {
 // ...
 } GeneratedClass.class @Example
 public class RandomClass {
 // ...
 } @Other
 public class GeneratedClass {
 // ...
 } javac ExampleProcessor
  101. Processing Rounds @Example
 public class RandomClass {
 // ...
 }

    ExampleProcessor OtherProcessor javac RandomClass.class out/ @Other
 public class GeneratedClass {
 // ...
 } GeneratedClass.class @Example
 public class RandomClass {
 // ...
 } @Other
 public class GeneratedClass {
 // ...
 } javac OtherProcessor
  102. Processing Rounds @Example
 public class RandomClass {
 // ...
 }

    ExampleProcessor OtherProcessor javac RandomClass.class out/ @Other
 public class GeneratedClass {
 // ...
 } GeneratedClass.class @Example
 public class RandomClass {
 // ...
 } @Other
 public class GeneratedClass {
 // ...
 } javac OtherProcessor public class OtherGenClass {
 // ...
 }
  103. Processing Rounds @Example
 public class RandomClass {
 // ...
 }

    ExampleProcessor OtherProcessor javac RandomClass.class out/ @Other
 public class GeneratedClass {
 // ...
 } GeneratedClass.class @Example
 public class RandomClass {
 // ...
 } @Other
 public class GeneratedClass {
 // ...
 } javac public class OtherGenClass {
 // ...
 }
  104. Processing Rounds @Example
 public class RandomClass {
 // ...
 }

    ExampleProcessor OtherProcessor javac RandomClass.class out/ @Other
 public class GeneratedClass {
 // ...
 } GeneratedClass.class @Example
 public class RandomClass {
 // ...
 } @Other
 public class GeneratedClass {
 // ...
 } javac public class OtherGenClass {
 // ...
 }
  105. Processing Rounds @Example
 public class RandomClass {
 // ...
 }

    ExampleProcessor OtherProcessor javac RandomClass.class out/ @Other
 public class GeneratedClass {
 // ...
 } GeneratedClass.class @Example
 public class RandomClass {
 // ...
 } @Other
 public class GeneratedClass {
 // ...
 } javac public class OtherGenClass {
 // ...
 }
  106. Processing Rounds @Example
 public class RandomClass {
 // ...
 }

    ExampleProcessor OtherProcessor javac RandomClass.class out/ @Other
 public class GeneratedClass {
 // ...
 } GeneratedClass.class @Example
 public class RandomClass {
 // ...
 } @Other
 public class GeneratedClass {
 // ...
 } javac public class OtherGenClass {
 // ...
 } OtherGenClass.class public class OtherGenClass {
 // ...
 }
  107. Processing Rounds @Example
 public class RandomClass {
 // ...
 }

    ExampleProcessor OtherProcessor javac RandomClass.class out/ @Other
 public class GeneratedClass {
 // ...
 } GeneratedClass.class @Example
 public class RandomClass {
 // ...
 } @Other
 public class GeneratedClass {
 // ...
 } javac public class OtherGenClass {
 // ...
 } ExampleProcessor OtherGenClass.class public class OtherGenClass {
 // ...
 }
  108. Processing Rounds @Example
 public class RandomClass {
 // ...
 }

    ExampleProcessor OtherProcessor javac RandomClass.class out/ @Other
 public class GeneratedClass {
 // ...
 } GeneratedClass.class @Example
 public class RandomClass {
 // ...
 } @Other
 public class GeneratedClass {
 // ...
 } javac public class OtherGenClass {
 // ...
 } OtherProcessor OtherGenClass.class public class OtherGenClass {
 // ...
 }
  109. Processing Rounds @Example
 public class RandomClass {
 // ...
 }

    ExampleProcessor OtherProcessor javac RandomClass.class out/ @Other
 public class GeneratedClass {
 // ...
 } GeneratedClass.class @Example
 public class RandomClass {
 // ...
 } @Other
 public class GeneratedClass {
 // ...
 } javac public class OtherGenClass {
 // ...
 } OtherGenClass.class public class OtherGenClass {
 // ...
 }
  110. Processing Rounds @Example
 public class RandomClass {
 // ...
 }

    ExampleProcessor OtherProcessor javac RandomClass.class out/ @Other
 public class GeneratedClass {
 // ...
 } GeneratedClass.class @Example
 public class RandomClass {
 // ...
 } @Other
 public class GeneratedClass {
 // ...
 } javac public class OtherGenClass {
 // ...
 } OtherGenClass.class public class OtherGenClass {
 // ...
 }
  111. Processing Rounds @Example
 public class RandomClass {
 // ...
 }

    ExampleProcessor OtherProcessor javac RandomClass.class out/ @Other
 public class GeneratedClass {
 // ...
 } GeneratedClass.class @Example
 public class RandomClass {
 // ...
 } @Other
 public class GeneratedClass {
 // ...
 } public class OtherGenClass {
 // ...
 } OtherGenClass.class public class OtherGenClass {
 // ...
 }
  112. None
  113. JavaCompiler

  114. ExampleProcessor JavaCompiler OtherProcessor

  115. ProcessingEnvironment ExampleProcessor JavaCompiler Filer OtherProcessor

  116. ProcessingEnvironment ExampleProcessor JavaCompiler Filer OtherProcessor init() init()

  117. ProcessingEnvironment ExampleProcessor JavaCompiler Filer OtherProcessor init() init()

  118. ProcessingEnvironment ExampleProcessor JavaCompiler Filer OtherProcessor init() init()

  119. ProcessingEnvironment ExampleProcessor JavaCompiler RoundEnvironment Filer OtherProcessor init() init()

  120. ProcessingEnvironment ExampleProcessor JavaCompiler RoundEnvironment Filer OtherProcessor init() process() init()

  121. ProcessingEnvironment ExampleProcessor JavaCompiler RoundEnvironment Filer OtherProcessor init() process() init()

  122. ProcessingEnvironment ExampleProcessor JavaCompiler RoundEnvironment Filer OtherProcessor init() process() init()

  123. ProcessingEnvironment ExampleProcessor JavaCompiler RoundEnvironment Filer OtherProcessor init() process() init()

  124. ProcessingEnvironment ExampleProcessor JavaCompiler RoundEnvironment Filer OtherProcessor init() process() init()

  125. ProcessingEnvironment ExampleProcessor JavaCompiler RoundEnvironment Filer OtherProcessor init() process() init()

  126. ProcessingEnvironment ExampleProcessor JavaCompiler RoundEnvironment Filer OtherProcessor init() process() init() process()

  127. ProcessingEnvironment ExampleProcessor JavaCompiler RoundEnvironment Filer OtherProcessor init() process() init() process()

  128. ProcessingEnvironment ExampleProcessor JavaCompiler RoundEnvironment Filer OtherProcessor init() process() init() process()

  129. ProcessingEnvironment ExampleProcessor JavaCompiler RoundEnvironment Filer OtherProcessor init() process() init() process()

  130. Parsing and Generation public class ExampleProcessor extends AbstractProcessor {
 //

    ...
 
 @Override public boolean process(
 Set<? extends TypeElement> annotations,
 RoundEnvironment env) {
 Set<? extends Element> elements
 = env.getElementsAnnotatedWith(Example.class);
 
 for (Element element : elements) {
 
 
 }
 return false;
 }
 }
  131. Parsing and Generation public class ExampleProcessor extends AbstractProcessor {
 //

    ...
 
 @Override public boolean process(
 Set<? extends TypeElement> annotations,
 RoundEnvironment env) {
 Set<? extends Element> elements
 = env.getElementsAnnotatedWith(Example.class);
 
 for (Element element : elements) {
 
 
 }
 return false;
 }
 } 
 
 
 
 
 
 
 
 
 // Look at attributes of 'element'.
 
 
 
 

  132. Parsing and Generation public class ExampleProcessor extends AbstractProcessor {
 //

    ...
 
 @Override public boolean process(
 Set<? extends TypeElement> annotations,
 RoundEnvironment env) {
 Set<? extends Element> elements
 = env.getElementsAnnotatedWith(Example.class);
 
 for (Element element : elements) {
 
 
 }
 return false;
 }
 } 
 
 
 
 
 
 
 
 
 // Look at attributes of 'element'.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 // Generate some code based on attributes.
 
 
 

  133. Parsing and Generation @Override public boolean process(
 Set<? extends TypeElement>

    annotations,
 RoundEnvironment env) {
 
 
 
 
 return false;
 }

  134. Parsing and Generation @Override public boolean process(
 Set<? extends TypeElement>

    annotations,
 RoundEnvironment env) {
 
 
 
 
 return false;
 }
 
 
 
 List<ExampleModel> models = parseExampleAnnotations(env);
  135. Parsing and Generation @Override public boolean process(
 Set<? extends TypeElement>

    annotations,
 RoundEnvironment env) {
 
 
 
 
 return false;
 }
 
 
 
 List<ExampleModel> models = parseExampleAnnotations(env); 
 
 
 
 
 
 
 
 
 
 List<ExampleModel> parseExampleAnnotations(RoundEnvironment env) {
 // ...
 }
  136. Parsing and Generation @Override public boolean process(
 Set<? extends TypeElement>

    annotations,
 RoundEnvironment env) {
 
 
 
 
 return false;
 }
 
 
 
 List<ExampleModel> models = parseExampleAnnotations(env); 
 
 
 
 for (ExampleModel model : models) {
 emitExampleCode(model);
 } 
 
 
 
 
 
 
 
 
 
 List<ExampleModel> parseExampleAnnotations(RoundEnvironment env) {
 // ...
 }
  137. Parsing and Generation @Override public boolean process(
 Set<? extends TypeElement>

    annotations,
 RoundEnvironment env) {
 
 
 
 
 return false;
 }
 
 
 
 List<ExampleModel> models = parseExampleAnnotations(env); 
 
 
 
 for (ExampleModel model : models) {
 emitExampleCode(model);
 } 
 
 
 
 
 
 
 
 
 
 List<ExampleModel> parseExampleAnnotations(RoundEnvironment env) {
 // ...
 } 
 
 
 
 
 
 
 
 
 ! ! 
 
 void emitExampleCode(ExampleModel model) {
 // ...
 }
  138. Parsing and Generation Element

  139. Parsing and Generation Element

  140. Parsing and Generation Element ExampleModel ! name: “Foo” package: “com.example”

    public: true
  141. Parsing and Generation Element ExampleModel ! name: “Foo” package: “com.example”

    public: true
  142. Parsing and Generation Element ExampleModel ! name: “Foo” package: “com.example”

    public: true ExampleModel ! name: “Foo” package: “com.example” public: true element:
  143. Parsing and Generation Element ExampleModel ! name: “Foo” package: “com.example”

    public: true ExampleModel ! name: “Foo” package: “com.example” public: true element: GeneratedClass
  144. Parsing and Generation Element ExampleModel ! name: “Foo” package: “com.example”

    public: true ExampleModel ! name: “Foo” package: “com.example” public: true element: GeneratedClass
  145. Bring Your Own Dependencies

  146. Bring Your Own Dependencies • Guava, Guava, Guava!

  147. Bring Your Own Dependencies • Guava, Guava, Guava! • JavaWriter

  148. Bring Your Own Dependencies • Guava, Guava, Guava! • JavaWriter

    • google/auto ‘common’
  149. Bring Your Own Dependencies • Guava, Guava, Guava! • JavaWriter

    • google/auto ‘common’ • AutoService (google/auto)
  150. JavaWriter

  151. JavaWriter JavaFileObject sourceFile = filer.createSourceFile(name, element);

  152. JavaWriter JavaFileObject sourceFile = filer.createSourceFile(name, element); ! ! ! JavaWriter

    writer = new JavaWriter(sourceFile.openWriter());
 writer.emitPackage("com.example")
 .emitAnnotation(Other.class)
 .beginType("GeneratedClass", "class")
 .emitSingleLineComment("...")
 .endType();
  153. JavaWriter JavaFileObject sourceFile = filer.createSourceFile(name, element); ! ! @com.example.Other
 public

    class GeneratedClass {
 // ...
 } ! ! ! JavaWriter writer = new JavaWriter(sourceFile.openWriter());
 writer.emitPackage("com.example")
 .emitAnnotation(Other.class)
 .beginType("GeneratedClass", "class")
 .emitSingleLineComment("...")
 .endType();
  154. JavaWriter JavaFileObject sourceFile = filer.createSourceFile(name, element); import com.example.Other; ! @Other


    public class GeneratedClass {
 // ...
 } ! ! ! JavaWriter writer = new JavaWriter(sourceFile.openWriter());
 writer.emitPackage("com.example")
 .emitImports(Other.class)
 .emitAnnotation(Other.class)
 .beginType("GeneratedClass", "class")
 .emitSingleLineComment("...")
 .endType();
  155. AutoService

  156. AutoService • Remember “ServiceLoader finds and creates”

  157. AutoService • Remember “ServiceLoader finds and creates” • AutoService generates

    service files from annotations
  158. AutoService • Remember “ServiceLoader finds and creates” • AutoService generates

    service files from annotations ! public class ExampleProcessor extends AbstractProcessor { // ... }
  159. AutoService • Remember “ServiceLoader finds and creates” • AutoService generates

    service files from annotations ! public class ExampleProcessor extends AbstractProcessor { // ... } @AutoService(Processor.class)
  160. Testing and Debugging

  161. Testing and Debugging • Google to the rescue!

  162. Testing and Debugging • Google to the rescue! • Guava,

    Guava, Guava!
  163. Testing and Debugging • Google to the rescue! • Guava,

    Guava, Guava! • compile-testing
  164. Testing and Debugging • Google to the rescue! • Guava,

    Guava, Guava! • compile-testing • Truth
  165. final class TestProcessors {
 static Iterable<? extends Processor> exampleProcessors() {


    return Collections.singletonList(
 new ExampleProcessor()
 );
 }
 }
  166. String input = Joiner.on('\n').join(
 "package test;",
 "import com.example.Example;",
 "@Example",
 "public

    class ExampleClass {",
 "}"
 );
  167. String input = Joiner.on('\n').join(
 "package test;",
 "import com.example.Example;",
 "@Example",
 "public

    class ExampleClass {",
 "}"
 ); JavaFileObject inputFile =
 JavaFileObjects.forSourceString("test.Test", input);
  168. JavaFileObject inputFile =
 JavaFileObjects.forSourceString("test.Test", input); String input = """\
 package

    test; 
 import com.example.Example; 
 @Example
 public class ExampleClass {
 } """ .stripIndent()
  169. String expected = Joiner.on('\n').join(
 "package test;",
 "import com.example.Other;",
 "@Other",
 "public

    class GeneratedClass {",
 "}"
 );
  170. String expected = Joiner.on('\n').join(
 "package test;",
 "import com.example.Other;",
 "@Other",
 "public

    class GeneratedClass {",
 "}"
 ); JavaFileObject expectedFile =
 JavaFileObjects.forSourceString("test.GeneratedClass", expected);
  171. ASSERT.about(javaSource())
 .that(inputFile)
 .processedWith(exampleProcessors())
 .compilesWithoutError()
 .and()
 .generatesSources(expectedFile);

  172. ASSERT.about(javaSource())
 .that(inputFile)
 .processedWith(exampleProcessors())
 .compilesWithoutError()
 .and()
 .generatesSources(expectedFile);

  173. ASSERT.about(javaSource())
 .that(inputFile)
 .processedWith(exampleProcessors())
 .compilesWithoutError()
 .and()
 .generatesSources(expectedFile);

  174. ASSERT.about(javaSource())
 .that(inputFile)
 .processedWith(exampleProcessors())
 .compilesWithoutError()
 .and()
 .generatesSources(expectedFile); String input = Joiner.on('\n').join(


    "package test;",
 "import com.example.Example;",
 "@Example",
 "public class ExampleClass {",
 "}"
 );
  175. ASSERT.about(javaSource())
 .that(inputFile)
 .processedWith(exampleProcessors())
 .compilesWithoutError()
 .and()
 .generatesSources(expectedFile); String input = Joiner.on('\n').join(


    "package test;",
 "import com.example.Example;",
 "@Example",
 "public class ExampleClass {",
 "}"
 ); final class TestProcessors {
 static Iterable<? extends Processor> exampleProcessors() {
 return Collections.singletonList(
 new ExampleProcessor()
 );
 }
 }
  176. ASSERT.about(javaSource())
 .that(inputFile)
 .processedWith(exampleProcessors())
 .compilesWithoutError()
 .and()
 .generatesSources(expectedFile); String input = Joiner.on('\n').join(


    "package test;",
 "import com.example.Example;",
 "@Example",
 "public class ExampleClass {",
 "}"
 ); final class TestProcessors {
 static Iterable<? extends Processor> exampleProcessors() {
 return Collections.singletonList(
 new ExampleProcessor()
 );
 }
 } String expected = Joiner.on('\n').join(
 "package test;",
 "import com.example.Other;",
 "@Other",
 "public class GeneratedClass {",
 "}"
 );
  177. ASSERT.about(javaSource())
 .that(inputFile)
 .processedWith(exampleProcessors())
 .compilesWithoutError()
 .and()
 .generatesSources(expectedFile); String input = Joiner.on('\n').join(


    "package test;",
 "import com.example.Example;",
 "@Example",
 "public class ExampleClass {",
 "}"
 ); final class TestProcessors {
 static Iterable<? extends Processor> exampleProcessors() {
 return Collections.singletonList(
 new ExampleProcessor()
 );
 }
 } String expected = Joiner.on('\n').join(
 "package test;",
 "import com.example.Other;",
 "@Other",
 "public class GeneratedClass {",
 "}"
 );
  178. public class ExampleProcessor extends AbstractProcessor {
 // ...
 
 @Override

    public boolean process(
 Set<? extends TypeElement> annotations,
 RoundEnvironment env) {
 Set<? extends Element> elements
 = env.getElementsAnnotatedWith(Example.class);
 for (Element element : elements) {
 System.out.println(element
 }
 return false;
 }
 } Debugging
  179. public class ExampleProcessor extends AbstractProcessor {
 // ...
 
 @Override

    public boolean process(
 Set<? extends TypeElement> annotations,
 RoundEnvironment env) {
 Set<? extends Element> elements
 = env.getElementsAnnotatedWith(Example.class);
 for (Element element : elements) {
 System.out.println(element
 }
 return false;
 }
 } Debugging
  180. Now What?

  181. None
  182. Questions?