Slide 1

Slide 1 text

Annotation Processing 101 Hannes Dorfmann @sockeqwe +HannesDorfmann hannesdorfmann.com

Slide 2

Slide 2 text

Annotation Processing ● Java 5 (Sep. 2004) ● JSR 269: 6 months after Java 5 released ● Plugin system for Annotation Processors

Slide 3

Slide 3 text

Annotation Processing ● Part of javac ● @Annotation based ● Generates java source code files

Slide 4

Slide 4 text

Reduces writing boilerplate code

Slide 5

Slide 5 text

public class MyActivity extends Activity { @InjectView(R.id.title) TextView title; @InjectView(R.id.text) TextView text; @InjectView(R.id.submit) Button submit; @InjectView(R.id.imageView) ImageView image; } Butter Knife http://jakewharton.github.io/butterknife/

Slide 6

Slide 6 text

public class MyActivity extends Activity { @Icicle String username; @Icicle int counter; } Icepick https://github.com/frankiesardo/icepick

Slide 7

Slide 7 text

public class ItemFragment extends Fragment { @Arg long itemId; @Arg int categoryId; } FragmentArgs https://github.com/sockeqwe/fragmentargs

Slide 8

Slide 8 text

@Parcel public class Person { String firstname; String lastname; int age; } Parceler http://parceler.org

Slide 9

Slide 9 text

public class AnimalsAdapter extends SupportAnnotatedAdapter implements AnimalsAdapterBinder { @ViewType(layout = R.layout.list_dog) public final int dog = 0; @ViewType(layout = R.layout.list_cat) public final int cat = 1; AnnotatedAdapter

Slide 10

Slide 10 text

public class AnimalsAdapter extends SupportAnnotatedAdapter implements AnimalsAdapterBinder { @Override public void bindViewHolder(DogViewHolder vh, int position) { Dog dog = (Dog) animals.get(position); vh.name.setText(dog.getName()); } AnnotatedAdapter

Slide 11

Slide 11 text

public class AnimalsAdapter extends SupportAnnotatedAdapter implements AnimalsAdapterBinder { @Override public void bindViewHolder(CatViewHolder vh, int position) { Cat cat = (Cat) animals.get(position); vh.image.setImageBitmap(cat.getImage()); } } AnnotatedAdapter https://github.com/sockeqwe/AnnotatedAdapter

Slide 12

Slide 12 text

Performance

Slide 13

Slide 13 text

Performance ● Compile time code generation ● Full JVM ● “Native” java code (as hand-written) ● No reflections!

Slide 14

Slide 14 text

LoganSquare https://github.com/bluelinelabs/LoganSquare Parsing 60 items 68 ms Gson Jackson LoganSquare 76 ms Serializing 60 items 74 ms 60 ms

Slide 15

Slide 15 text

LoganSquare https://github.com/bluelinelabs/LoganSquare Parsing 60 items 68 ms Gson Jackson LoganSquare 76 ms 17 Serializing 60 items 74 ms 60 ms 10

Slide 16

Slide 16 text

Dagger 2 ● Google Scale ● Replacing Dagger 1 with Dagger 2 ● Saving 13 % CPU by just moving DI https://www.youtube.com/watch?v=oK_XtfXPkqw (36:00)

Slide 17

Slide 17 text

Otto 1.3.7 https://github.com/greenrobot/EventBus EventBus 2.4 2000 4000 18000 16000 8000 12000 EventBus 3.0

Slide 18

Slide 18 text

Otto 1.3.7 https://github.com/greenrobot/EventBus EventBus 2.4 EventBus 3.0 2000 4000 18000 16000 8000 12000 EventBus 3.0

Slide 19

Slide 19 text

Limitation ● Can generate only new files ● Can’t manipulate already existing files ○ Bytecode manipulation (ASM, Afterburn) ○ AST manipulation (Project Lombok)

Slide 20

Slide 20 text

Not debuggable!

Slide 21

Slide 21 text

Example Pizza Store

Slide 22

Slide 22 text

public interface Meal { public float getPrice(); } public class MargheritaPizza implements Meal { @Override public float getPrice() { return 6f; } }

Slide 23

Slide 23 text

public class CalzonePizza implements Meal { @Override public float getPrice() { return 8.5f; } } public class Tiramisu implements Meal { @Override public float getPrice() { return 4.5f; } }

Slide 24

Slide 24 text

public class PizzaStore { private MealFactory factory = new MealFactory(); public static void main(String[] args) throws IOException { PizzaStore pizzaStore = new PizzaStore(); Meal meal = pizzaStore.order( readConsole() ); System.out.println("Bill: $" + meal.getPrice()); } public Meal order(String mealName) { return factory.create(mealName); } }

Slide 25

Slide 25 text

public class MealFactory { public Meal create(String id) { if ("Margherita".equals(id)) return new MargheritaPizza(); if ("Calzone".equals(id)) return new CalzonePizza(); if ("Tiramisu".equals(id)) return new Tiramisu(); throw new IllegalArgumentException("Unknown meal”); } }

Slide 26

Slide 26 text

@Target(ElementType.TYPE) public @interface Factory { String id(); Class type(); }

Slide 27

Slide 27 text

@Factory( id = "Margherita", type = Meal.class ) public class MargheritaPizza implements Meal { @Override public float getPrice() { return 6f; } }

Slide 28

Slide 28 text

@Factory( id = "Calzone", type = Meal.class ) public class CalzonePizza implements Meal { @Override public float getPrice() { return 8.5f; } }

Slide 29

Slide 29 text

Pizza Store Factory 1. Only classes can be @Factory

Slide 30

Slide 30 text

Pizza Store Factory 1. Only classes can be @Factory 2. @Factory classes must have empty constructor

Slide 31

Slide 31 text

Pizza Store Factory 1. Only classes can be @Factory 2. @Factory classes must have empty constructor 3. Same types are grouped to one factory

Slide 32

Slide 32 text

Pizza Store Factory 1. Only classes can be @Factory 2. @Factory classes must have empty constructor 3. Same types are grouped to one factory 4. id is String and must be unique in factory group

Slide 33

Slide 33 text

Pizza Store Factory 1. Only classes can be @Factory 2. @Factory classes must have empty constructor 3. Same types are grouped to one factory 4. id is String and must be unique in factory group 5. @Factory classes must inherit from specified type

Slide 34

Slide 34 text

@Factory( id = "Margherita", type = Meal.class ) public class MargheritaPizza implements Meal { @Override public float getPrice() { return 6f; } }

Slide 35

Slide 35 text

@Factory( id = "Margherita", type = Meal.class ) public class MargheritaPizza implements Meal { @Override public float getPrice() { return 6f; } }

Slide 36

Slide 36 text

public class FactoryProcessor extends AbstractProcessor { private Types typeUtils; private Elements elementUtils; private Filer filer; private Messager messager; private Map factoryClasses; @Override public synchronized void init(ProcessingEnvironment processingEnv) { typeUtils = processingEnv.getTypeUtils(); elementUtils = processingEnv.getElementUtils(); filer = processingEnv.getFiler(); messager = processingEnv.getMessager(); }

Slide 37

Slide 37 text

public class FactoryProcessor extends AbstractProcessor { @Override public Set getSupportedAnnotationTypes() { Set annotations = new LinkedHashSet(); annotations.add(Factory.class.getCanonicalName()); return annotations; }

Slide 38

Slide 38 text

public class FactoryProcessor extends AbstractProcessor { @Override public boolean process(Set extends TypeElement> annotations, RoundEnvironment rv) { for (Element annotatedElement : rv.getElementsAnnotatedWith(Factory.class)) { } } }

Slide 39

Slide 39 text

@Example public class Foo { private int a; private Other other; public Foo () { ... } public void setA ( int newA ) { ... } }

Slide 40

Slide 40 text

@Example public class Foo { private int a; private Other other; public Foo () { ... } public void setA ( int newA ) { ... } } TypeElement

Slide 41

Slide 41 text

@Example public class Foo { private int a; private Other other; public Foo () { ... } public void setA ( int newA ) { ... } } TypeElement VariableElement

Slide 42

Slide 42 text

@Example public class Foo { private int a; private Other other; public Foo () { ... } public void setA ( int newA ) { ... } } TypeElement VariableElement VariableElement

Slide 43

Slide 43 text

@Example public class Foo { private int a; private Other other; public Foo () { ... } public void setA ( int newA ) { ... } } TypeElement VariableElement VariableElement ExecuteableElement

Slide 44

Slide 44 text

@Example public class Foo { private int a; private Other other; public Foo () { ... } public void setA ( int newA ) { ... } } TypeElement VariableElement VariableElement ExecuteableElement ExecuteableElement

Slide 45

Slide 45 text

@Example public class Foo { private int a; private Other other; public Foo () { ... } public void setA ( int newA ) { ... } } TypeElement VariableElement VariableElement ExecuteableElement ExecuteableElement TypeElement

Slide 46

Slide 46 text

@Example public class Foo { private int a; private Other other; public Foo () { ... } public void setA ( int newA ) { ... } } TypeElement VariableElement VariableElement ExecuteableElement ExecuteableElement TypeElement

Slide 47

Slide 47 text

@Example public class Foo { private int a; private Other other; public Foo () { ... } public void setA ( int newA ) { ... } } TypeElement VariableElement VariableElement ExecuteableElement ExecuteableElement TypeElement

Slide 48

Slide 48 text

@Example public class Foo { private int a; private Other other; public Foo () { ... } public void setA ( int newA ) { ... } } TypeMirror

Slide 49

Slide 49 text

public class FactoryProcessor extends AbstractProcessor { @Override public synchronized void init(ProcessingEnvironment processingEnv); @Override public Set getSupportedAnnotationTypes(); @Override public boolean process(Set extends TypeElement> annotations, RoundEnvironment rv); }

Slide 50

Slide 50 text

FactoryProcessor.jar - com - example - FactoryProcessor.class - META-INF - services - javax.annotation.processing.Processor

Slide 51

Slide 51 text

@AutoService(Processor.class) public class FactoryProcessor extends AbstractProcessor { @Override public synchronized void init(ProcessingEnvironment processingEnv); @Override public Set getSupportedAnnotationTypes(); @Override public boolean process(Set extends TypeElement> annotations, RoundEnvironment rv); }

Slide 52

Slide 52 text

Pizza Store Factory 1. Only classes can be @Factory 2. @Factory classes must have empty constructor 3. Same types are grouped to one factory 4. id is String and must be unique in factory group 5. @Factory classes must inherit from specified type

Slide 53

Slide 53 text

public boolean process(Set<> annotations, RoundEnvironment rv) { for (Element annotatedElement : rv.getElementsAnnotatedWith(Factory.class)) { if (! (annotatedElement instanceof TypeElement) ){ ... } } }

Slide 54

Slide 54 text

public boolean process(Set<> annotations, RoundEnvironment rv) { for (Element annotatedElement : rv.getElementsAnnotatedWith(Factory.class)) { if (! (annotatedElement instanceof TypeElement) ){ ... } } }

Slide 55

Slide 55 text

public boolean process(Set<> annotations, RoundEnvironment rv) { for (Element annotatedElement : rv.getElementsAnnotatedWith(Factory.class)) { if (annotatedElement.getKind() != ElementKind.CLASS) { messager.printMessage( Diagnostic.Kind.ERROR, "Only classes can be annotated with @Factory", annotatedElement ); } } }

Slide 56

Slide 56 text

public boolean process(Set<> annotations, RoundEnvironment rv) { for (Element annotatedElement : rv.getElementsAnnotatedWith(Factory.class)) { if (annotatedElement.getKind() != ElementKind.CLASS) { error( annotatedElement, "Only classes can be annotated with @Factory"); } } } public void error(Element e, String msg) { messager.printMessage(Diagnostic.Kind.ERROR, "Error", e); }

Slide 57

Slide 57 text

public boolean process(Set<> annotations, RoundEnvironment rv) { for (Element annotatedElement : rv.getElementsAnnotatedWith(Factory.class)) { if (annotatedElement.getKind() != ElementKind.CLASS) { error( annotatedElement, "Only classes can be annotated with @Factory"); annotatedElement = null; } annotatedElement.getSimpleName(); } }

Slide 58

Slide 58 text

Caused by: java.lang.NullPointerException at com.example.processor.FactoryProcessor.process(FactoryProcessor.java:161) at com.sun.tools.javac.processing.JavacProcessingEnvironment.callProcessor (JavacProcessingEnvironment.java:793) at com.sun.tools.javac.processing.JavacProcessingEnvironment. discoverAndRunProcs(JavacProcessingEnvironment.java:722) at com.sun.tools.javac.processing.JavacProcessingEnvironment.access$1700 (JavacProcessingEnvironment.java:97) ... 32 more

Slide 59

Slide 59 text

public boolean process(Set<> annotations, RoundEnvironment rv) { for (Element annotatedElement : rv.getElementsAnnotatedWith(Factory.class)) { if (annotatedElement.getKind() != ElementKind.CLASS) { error( annotatedElement, "Only classes can be annotated with @Factory"); annotatedElement = null; } annotatedElement.getSimpleName(); } }

Slide 60

Slide 60 text

public boolean process(Set<> annotations, RoundEnvironment rv) { for (Element annotatedElement : rv.getElementsAnnotatedWith(Factory.class)) { if (annotatedElement.getKind() != ElementKind.CLASS) { error( annotatedElement, "Only classes can be annotated with @Factory"); } checkOtherThings( annotatedElement ); } } public void checkOtherThings(Element element) { ... }

Slide 61

Slide 61 text

public boolean process(Set<> annotations, RoundEnvironment rv) { try { for (Element annotatedElement : rv.getElementsAnnotatedWith(Factory.class)) { if (annotatedElement.getKind() != ElementKind.CLASS) { error( annotatedElement, "Only classes can be annotated with @Factory"); } checkOtherThings( annotatedElement ); } } catch (ProcessingException e) { error(e.getElement(), e.getMessage()); } }

Slide 62

Slide 62 text

public void checkOtherThings(Element element) throws ProcessingException

Slide 63

Slide 63 text

public void checkOtherThings(Element element) throws ProcessingException public class ProcessingException extends Exception { Element element; public ProcessingException(Element element, String msg, Object... args) { super(String.format(msg, args)); this.element = element; } public Element getElement() { return element; } }

Slide 64

Slide 64 text

Pizza Store Factory 1. Only classes can be @Factory 2. @Factory classes must have empty constructor 3. Same types are grouped to one factory 4. id is String and must be unique in factory group 5. @Factory classes must inherit from specified type

Slide 65

Slide 65 text

public void checkConstructor(TypeElement e) throws ProcessingException { for (Element enclosed : e.getEnclosedElements()) { if (enclosed.getKind() == ElementKind.CONSTRUCTOR) { ExecutableElement constructorElement = (ExecutableElement) enclosed; if (constructorElement.getParameters().size() == 0 && constructorElement.getModifiers().contains(Modifier.PUBLIC)) { return; } } throw new ProcessingException(e, "No public empty constructor"); }

Slide 66

Slide 66 text

Pizza Store Factory 1. Only classes can be @Factory 2. @Factory classes must have empty constructor 3. Same types are grouped to one factory 4. id is String and must be unique in factory group 5. @Factory classes must inherit from specified type

Slide 67

Slide 67 text

public class FactoryAnnotatedClass { TypeElement annotatedClassElement; String id; String qualifiedGroupClassName; public FactoryAnnotatedClass(TypeElement element) throws ProcessingException { this.annotatedClassElement = classElement; } }

Slide 68

Slide 68 text

public FactoryAnnotatedClass(TypeElement element) throws ProcessingException { Factory annotation = classElement.getAnnotation(Factory.class); this.id = annotation.id(); if (StringUtils.isEmpty(id)) { throw new ProcessingException(classElement, "id() is null or empty!); } }

Slide 69

Slide 69 text

public FactoryAnnotatedClass(TypeElement element) throws ProcessingException { Factory annotation = classElement.getAnnotation(Factory.class); try { Class> clazz = annotation.type(); qualifiedGroupClassName = clazz.getCanonicalName(); } catch (MirroredTypeException mte) { } }

Slide 70

Slide 70 text

public FactoryAnnotatedClass(TypeElement element) throws ProcessingException { Factory annotation = classElement.getAnnotation(Factory.class); try { Class> clazz = annotation.type(); qualifiedGroupClassName = clazz.getCanonicalName(); } catch (MirroredTypeException mte) { DeclaredType classTypeMirror = (DeclaredType) mte.getTypeMirror(); TypeElement classTypeElement = (TypeElement) classTypeMirror.asElement(); qualifiedGroupClassName = classTypeElement.getQualifiedName().toString(); } }

Slide 71

Slide 71 text

public class FactoryGroupedClasses { String qualifiedClassName; Map itemsMap = new LinkedHashMap(); public FactoryGroupedClasses(String qualifiedClassName) { this.qualifiedClassName = qualifiedClassName; } }

Slide 72

Slide 72 text

public class FactoryGroupedClasses { public void add(FactoryAnnotatedClass toInsert) throws ProcessingException { } }

Slide 73

Slide 73 text

public class FactoryGroupedClasses { public void add(FactoryAnnotatedClass toInsert) throws ProcessingException { FactoryAnnotatedClass existing = itemsMap.get(toInsert.getId()); } }

Slide 74

Slide 74 text

public class FactoryGroupedClasses { public void add(FactoryAnnotatedClass toInsert) throws ProcessingException { FactoryAnnotatedClass existing = itemsMap.get(toInsert.getId()); if (existing != null) { throw new ProcessingException(toInsert.getTypeElement(), "Conflict: Class with same id found“ ); } } }

Slide 75

Slide 75 text

public class FactoryGroupedClasses { public void add(FactoryAnnotatedClass toInsert) throws ProcessingException { FactoryAnnotatedClass existing = itemsMap.get(toInsert.getId()); if (existing != null) { throw new ProcessingException(toInsert.getTypeElement(), "Conflict: Class with same id found“ ); } itemsMap.put(toInsert.getId(), toInsert); } }

Slide 76

Slide 76 text

FactoryProcessor Map FactoryGroupedClasses Map FactoryAnnotatedClass String id

Slide 77

Slide 77 text

public boolean process(Set<> annotations, RoundEnvironment rv) { try { for (Element annotatedElement : rv.getElementsAnnotatedWith(Factory.class)) { } } catch (ProcessingException e) { ... } }

Slide 78

Slide 78 text

public boolean process(Set<> annotations, RoundEnvironment rv) { try { for (Element annotatedElement : rv.getElementsAnnotatedWith(Factory.class)) { FactoryAnnotatedClass annotatedClass = new FactoryAnnotatedClass( annotatedElement ); } } catch (ProcessingException e) { ... } }

Slide 79

Slide 79 text

public boolean process(Set<> annotations, RoundEnvironment rv) { try { for (Element annotatedElement : rv.getElementsAnnotatedWith(Factory.class)) { FactoryAnnotatedClass annotatedClass = new FactoryAnnotatedClass( annotatedElement ); FactoryGroupedClasses factoryClass = getOrCreateFactoryClass( annotatedClass.getQualifiedGroupName() ); } } catch (ProcessingException e) { ... } }

Slide 80

Slide 80 text

public boolean process(Set<> annotations, RoundEnvironment rv) { try { for (Element annotatedElement : rv.getElementsAnnotatedWith(Factory.class)) { FactoryAnnotatedClass annotatedClass = new FactoryAnnotatedClass( annotatedElement ); FactoryGroupedClasses factoryClass = getOrCreateFactoryClass( annotatedClass.getQualifiedGroupName()); factoryClass.add(annotatedClass); } } catch (ProcessingException e) { ... } }

Slide 81

Slide 81 text

Pizza Store Factory 1. Only classes can be @Factory 2. @Factory classes must have empty constructor 3. Same types are grouped to one factory 4. id is String and must be unique in factory group 5. @Factory classes must inherit from specified type

Slide 82

Slide 82 text

public void checkInheritance(FactoryAnnotatedClass ac) throws ProcessingException { TypeElement currentClass = ac.getTypeElement(); }

Slide 83

Slide 83 text

public void checkInheritance(FactoryAnnotatedClass ac) throws ProcessingException { TypeElement currentClass = ac.getTypeElement(); while (true) { TypeMirror superClassType = currentClass.getSuperclass(); currentClass = (TypeElement) typeUtils.asElement(superClassType); } }

Slide 84

Slide 84 text

public void checkInheritance(FactoryAnnotatedClass ac) throws ProcessingException { TypeElement currentClass = ac.getTypeElement(); while (true) { TypeMirror superClassType = currentClass.getSuperclass(); if (superClassType.getKind() == TypeKind.NONE) throw new ProcessingException( classElement, "Class doesn’t inherit Meal” ); currentClass = (TypeElement) typeUtils.asElement(superClassType); } }

Slide 85

Slide 85 text

public void checkInheritance(FactoryAnnotatedClass ac) throws ProcessingException { TypeElement currentClass = ac.getTypeElement(); while (true) { TypeMirror superClassType = currentClass.getSuperclass(); if (superClassType.getKind() == TypeKind.NONE) throw new ProcessingException( classElement, "Class doesn’t inherit Meal” ); if (superClassType.toString().equals( ac.getQualifiedFactoryGroupName() ) ) return; currentClass = (TypeElement) typeUtils.asElement(superClassType); } }

Slide 86

Slide 86 text

Code generation

Slide 87

Slide 87 text

private Map factoryClasses; public boolean process(Set<> annotations, RoundEnvironment rv) { try { ... } catch (ProcessingException e) { ... } for (FactoryGroupedClasses factoryClass : factoryClasses.values()) { factoryClass.generateCode(elementUtils, filer); } }

Slide 88

Slide 88 text

public void generateCode(Elements elementUtils, Filer filer) throws IOException { MethodSpec.Builder method = MethodSpec.methodBuilder("create") .addModifiers(Modifier.PUBLIC) .addParameter(String.class, "id") .returns(TypeName.get(superClassName.asType())); }

Slide 89

Slide 89 text

public Meal create(String id) { }

Slide 90

Slide 90 text

public void generateCode(Elements elementUtils, Filer filer) throws IOException { MethodSpec.Builder method = MethodSpec.methodBuilder("create") ... for (FactoryAnnotatedClass item : itemsMap.values()) { method .beginControlFlow("if ($S.equals(id))", item.getId()) .addStatement("return new $L()", item.getTypeElement().getQualifiedName().toString()) .endControlFlow(); } }

Slide 91

Slide 91 text

public Meal create(String id) { if ("Margherita".equals(id)) return new MargheritaPizza(); if ("Calzone".equals(id)) return new CalzonePizza(); if ("Tiramisu".equals(id)) return new Tiramisu(); }

Slide 92

Slide 92 text

public void generateCode(Elements elementUtils, Filer filer) throws IOException { MethodSpec.Builder method = MethodSpec.methodBuilder("create") ... method.addStatement( "throw new IllegalArgumentException($S + id)", "Unknown id = " ); }

Slide 93

Slide 93 text

public Meal create(String id) { if ("Margherita".equals(id)) return new MargheritaPizza(); if ("Calzone".equals(id)) return new CalzonePizza(); if ("Tiramisu".equals(id)) return new Tiramisu(); throw new IllegalArgumentException( "Unknown id = ” +id ); }

Slide 94

Slide 94 text

public void generateCode(Elements elementUtils, Filer filer) throws IOException { MethodSpec.Builder method = MethodSpec.methodBuilder("create") ... TypeSpec typeSpec = TypeSpec.classBuilder( factoryClassName ) .addMethod( method.build() ).build(); // Write MealFactory.java JavaFile.builder(packageName, typeSpec).build().writeTo(filer); }

Slide 95

Slide 95 text

public class MealFactory { public Meal create(String id) { if ("Margherita".equals(id)) return new MargheritaPizza(); if ("Calzone".equals(id)) return new CalzonePizza(); if ("Tiramisu".equals(id)) return new Tiramisu(); throw new IllegalArgumentException( "Unknown id = ” +id ); } }

Slide 96

Slide 96 text

Attempt to recreate a file for type com.example.MealFactory

Slide 97

Slide 97 text

Processing Rounds Round Input Output 1. PizzaStore.java Meal.java CalzonePizza.java Tiramisu.java Magerita.java MealFactory.java

Slide 98

Slide 98 text

Processing Rounds Round Input Output 1. PizzaStore.java Meal.java CalzonePizza.java Tiramisu.java Magerita.java MealFactory.java 2. MealFactory.java -- none --

Slide 99

Slide 99 text

Processing Rounds Round Input Output 1. PizzaStore.java Meal.java CalzonePizza.java Tiramisu.java Magerita.java MealFactory.java 2. MealFactory.java -- none -- 3. -- none -- -- none --

Slide 100

Slide 100 text

public class FactoryProcessor extends AbstractProcessor { private Map factoryClasses; public boolean process(Set<> annotations, RoundEnvironment rv) { try { // scan annotations } catch (ProcessingException e) { ... } for (FactoryGroupedClasses factoryClass : factoryClasses.values()) { factoryClass.generateCode(elementUtils, filer); } } }

Slide 101

Slide 101 text

public class FactoryProcessor extends AbstractProcessor { private Map factoryClasses; public boolean process(Set<> annotations, RoundEnvironment rv) { try { // scan annotations } catch (ProcessingException e) { ... } for (FactoryGroupedClasses factoryClass : factoryClasses.values()) { factoryClass.generateCode(elementUtils, filer); } } }

Slide 102

Slide 102 text

public class FactoryProcessor extends AbstractProcessor { private Map factoryClasses; public boolean process(Set<> annotations, RoundEnvironment rv) { try { // scan annotations } catch (ProcessingException e) { ... } for (FactoryGroupedClasses factoryClass : factoryClasses.values()) { factoryClass.generateCode(elementUtils, filer); } } }

Slide 103

Slide 103 text

public class FactoryProcessor extends AbstractProcessor { private Map factoryClasses; public boolean process(Set<> annotations, RoundEnvironment rv) { try { // scan annotations } catch (ProcessingException e) { ... } for (FactoryGroupedClasses factoryClass : factoryClasses.values()) { factoryClass.generateCode(elementUtils, filer); } factoryClasses.clear(); } }

Slide 104

Slide 104 text

Instantiation

Slide 105

Slide 105 text

public class PizzaStore { private MealFactory factory = new MealFactory(); public static void main(String[] args) throws IOException { PizzaStore pizzaStore = new PizzaStore(); Meal meal = pizzaStore.order( readConsole() ); System.out.println("Bill: $" + meal.getPrice()); } public Meal order(String mealName) { return factory.create(mealName); } }

Slide 106

Slide 106 text

No content

Slide 107

Slide 107 text

Instantiation using Reflections ButterKnife.inject(Activity);

Slide 108

Slide 108 text

Instantiation using Reflections ButterKnife.inject(Activity); try { Class> injector = Class.forName(activityClassName + "$$ViewInjector"); } catch (ClassNotFoundException e) { ... }

Slide 109

Slide 109 text

We are hiring ;-) http://hannesdorfmann.com https://github.com/sockeqwe/annotationprocessing101