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

How can we write less code by generating code?

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on.

How can we write less code by generating code?

Avatar for Gil Goldzweig

Gil Goldzweig

April 24, 2018
Tweet

More Decks by Gil Goldzweig

Other Decks in Programming

Transcript

  1. Annotation Processor tool - APT • A tool for the

    Javac(Java compiler) • Added JDK 1.5 • Reads & Process @Annotated sources
  2. Chain of events Write (.java) Compile (.class) Package (.jar) Dex

    (.dex) Package (.apk) APT (.java) Project lifecycle - APT
  3. Chain of events Write (.java) Compile (.class) Package (.jar) Dex

    (.dex) Package (.apk) Project lifecycle - android
  4. Before - Gencycler ViewHolder class LectureViewHolder extends RecyclerView.ViewHolder { TextView

    title; TextView description; TextView date; LectureViewHolder(View itemView) { super(itemView); title = itemView.findViewById(R.id.lecture_title); description = itemView.findViewById(R.id.lecture_desc); date = itemView.findViewById(R.id.lecture_date); } }
  5. Before - Gencycler Adapter - OnCreateViewHolder public class LectureAdapter extends

    RecyclerView.Adapter<LectureViewHolder> { … @Override public LectureViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { return new LectureViewHolder(inflater .inflate(R.layout.item_lecture, parent, false)); } }
  6. Before - Gencycler Adapter - GetItemCount public class LectureAdapter extends

    RecyclerView.Adapter<LectureViewHolder> { … @Override public int getItemCount() { return lectures.size(); } }
  7. Before - Gencycler Adapter - GetItemViewType public class LectureAdapter extends

    RecyclerView.Adapter<LectureViewHolder> { … @Override public int getItemViewType(int position) { return super.getItemViewType(position); } }
  8. Before - Gencycler RecyclerView - OnBindViewHolder public class LectureAdapter extends

    RecyclerView.Adapter<LectureViewHolder> { … @Override public void onBindViewHolder(LectureViewHolder holder, int position) { Lecture lecture = lectures.get(position); } }
  9. RecyclerView + Gencycler @RecyclerAdapter(data = Lecture.class, ui = R.layout.item_lecture) public

    class LectureAdapter extends GeneratedLectureAdapter { } Recyclerview - Gencycler
  10. RecyclerView + Gencycler @RecyclerAdapter(data = Lecture.class, ui = R.layout.item_lecture) public

    class LectureAdapter extends GeneratedLectureAdapter { @Override public void onBindLectureViewHolder(LectureViewHolder holder, int position, @NotNull Lecture lecture) { //Actual logic (setText etc… ) } } Recyclerview - Gencycler
  11. Target - Limit where the annotation can be placed •

    Type(Class) • Field • Method • Parameter • AnnotationType • Constructor • Package • LocalVariable (Java 1.8) • TypeParameter (Java 1.8)
  12. Retention - When will the annotation can be used •

    Source(Annotation processor) • Runtime(Reflection) • Class(Annotation processor + Reflection)
  13. Reflection Reflection • Create new instances of objects • Invoke

    methods • Examine properties of classes (fields, methods, constructors) • Modify field values
  14. AbstractProcessor ProcessingEnvironment • Filer - used to create new source,

    class, or auxiliary files • Opptions • Messenger - Reports errors, warnings, and other notices • Utility methods for using elements/types
  15. AbstractProcessor public class RecyclerProcessor extends AbstractProcessor { … @Override public

    Set<String> getSupportedAnnotationTypes() { return ImmutableSet.of(RecyclerAdapter.class .getCanonicalName()); } } Processor
  16. AbstractProcessor public class RecyclerProcessor extends AbstractProcessor { … @Override public

    SourceVersion getSupportedSourceVersion() { return SourceVersion.latestSupported(); } } Processor
  17. AbstractProcessor public class RecyclerProcessor extends AbstractProcessor { … @Override public

    boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) { } } Processor
  18. AbstractProcessor public class RecyclerProcessor extends AbstractProcessor { … @Override public

    boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) { } } Processor
  19. AbstractProcessor public class RecyclerProcessor extends AbstractProcessor { … @Override public

    boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) { } } Processor
  20. AbstractProcessor Java sources APT Completed Round one - sources Processing

    rounds LectureAdapter.java OtherAdapter.java Processing rounds
  21. AbstractProcessor public class RecyclerProcessor extends AbstractProcessor { … @Override public

    boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) { //RoundEnvironment will hold information about //the LectureAdapter.java & OtherAdapter.Java } } Processor
  22. AbstractProcessor Java sources APT Completed Round one - new source

    files generated Processing rounds LectureGenrated.java OtherGenrated.java LectureAdapter.java OtherAdapter.java Processing rounds
  23. AbstractProcessor Processing rounds Java sources APT Completed Round one -

    Completed Processing rounds LectureGenrated.java OtherGenrated.java LectureAdapter.java OtherAdapter.java Processing rounds
  24. AbstractProcessor Processing rounds Java sources APT Completed Round two -

    generated sources Processing rounds LectureGenrated.java OtherGenrated.java LectureAdapter.java OtherAdapter.java Processing rounds Processing rounds Processing rounds
  25. AbstractProcessor Processing rounds Java sources APT Completed Processing rounds LectureAdapter.java

    OtherAdapter.java LectureGenrated.java OtherGenrated.java Round two - generated sources Processing rounds
  26. AbstractProcessor Processing rounds Java sources APT Completed LectureGenrated.java OtherGenrated.java Round

    two - Completed Processing rounds LectureAdapter.java OtherAdapter.java Processing rounds
  27. • Automatic ◦ Java/KotlinPoet (open source library created by square)

    • Manual ◦ Writer Code generation Code generation
  28. + Easy usage + Very good documentation + Language objects

    oriented Automatic - Java/kotlinPoet - Very verbose code
  29. + Easy usage Manual - StringBuilder - Not language objects

    oriented - Hard to maintain properly Manual - Writer
  30. package com.example.helloworld; public final class HelloWorld { public static void

    main(String[] args) { System.out.println("Hello, JavaPoet!"); } } What we want to generate
  31. JavaPoet - method MethodSpec main = MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .returns(void.class)

    .addParameter(String[].class, "args") .addStatement("System.out.println(\"Hello, JavaPoet!\")") .build();
  32. JavaPoet - method MethodSpec main = MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .returns(void.class)

    .addParameter(String[].class, "args") .addStatement("System.out.println(\"Hello, JavaPoet!\")") .build();
  33. JavaPoet - method MethodSpec main = MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .returns(void.class)

    .addParameter(String[].class, "args") .addStatement("System.out.println(\"Hello, JavaPoet!\")") .build();
  34. JavaPoet - method MethodSpec main = MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .returns(void.class)

    .addParameter(String[].class, "args") .addStatement("System.out.println(\"Hello, JavaPoet!\")") .build();
  35. JavaPoet - method MethodSpec main = MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .returns(void.class)

    .addParameter(String[].class, "args") .addStatement("System.out.println(\"Hello, JavaPoet!\")") .build();
  36. JavaPoet - method MethodSpec main = MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .returns(void.class)

    .addParameter(String[].class, "args") .addStatement("System.out.println(\"Hello, JavaPoet!\")") .build();
  37. MethodSpec public final class HelloWorld { public static void main(String[]

    args) { System.out.println("Hello, JavaPoet!"); } } JavaPoet - class JavaPoet - class JavaPoet - class / generated
  38. package com.example.helloworld; public final class HelloWorld { public static void

    main(String[] args) { System.out.println("Hello, JavaPoet!"); } } JavaPoet - file / generated
  39. package com.example.helloworld; public final class HelloWorld { public static void

    main(String[] args) { System.out.println("Hello, JavaPoet!"); } } JavaPoet - file / generated
  40. JavaPoet MethodSpec main = MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .returns(void.class) .addParameter(String[].class, "args")

    .addStatement("System.out.println(\"Hello, JavaPoet!\")") .build(); TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld") .addModifiers(Modifier.PUBLIC, Modifier.FINAL) .addMethod(main) .build(); JavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld) .build(); javaFile.writeTo(processingEnv.getFiler()); JavaPoet JavaPoet - code needed
  41. JavaPoet - file Manual Writer codeWriter = procesingEnc.filer .createSource(StandardLocation.SOURCE_OUTPUT) .openWriter();

    codeWriter .append("package com.example.helloworld;") .append("\n\n") .append("public final class HelloWorld {\n") .append(" ") .append("public static void main(String[] args) {\n") .append(" ") .append("System.out.println(\"Hello, JavaPoet!\");\n") .append(" }\n") .append("}");
  42. Benefits • No Runtime performance impact • Write your code

    generator once • Trust the generated code Benefits
  43. Here are some helpful links to help you build your

    own processor :) Annotation Processing : Don’t Repeat Yourself, Generate Your Code. Annotation processing 101 @Eliminate(Boilerplate) JavaPoet KotlinPoet Gencycler