Slide 1

Slide 1 text

Mechanisms of Metaprogramming @JakeWharton

Slide 2

Slide 2 text

Metaprogramming

Slide 3

Slide 3 text

Metaprogramming Runtime

Slide 4

Slide 4 text

Metaprogramming Runtime Compile-time vs.

Slide 5

Slide 5 text

Metaprogramming Runtime Compile-time vs. Additive

Slide 6

Slide 6 text

Metaprogramming Runtime Compile-time vs. Additive Mutating vs.

Slide 7

Slide 7 text

Metaprogramming Runtime Compile-time Additive Mutating

Slide 8

Slide 8 text

Metaprogramming Runtime Compile-time Additive Mutating

Slide 9

Slide 9 text

Metaprogramming Runtime Compile-time Additive Mutating Reflection / Parser

Slide 10

Slide 10 text

Metaprogramming Runtime Compile-time Additive Mutating Reflection / Parser Source generator / Bytecode generator

Slide 11

Slide 11 text

Metaprogramming Runtime Compile-time Additive Mutating Reflection / Parser Source generator / Bytecode generator Source transformer / Bytecode transformer

Slide 12

Slide 12 text

Metaprogramming Runtime Compile-time Additive Mutating Reflection / Parser Source generator / Bytecode generator Source transformer / Bytecode transformer

Slide 13

Slide 13 text

SomeLibrary.doSomething(User.class);

Slide 14

Slide 14 text

SomeLibrary.doSomething(User.class); AnotherLibrary.doSomething(this);

Slide 15

Slide 15 text

SomeLibrary.doSomething(User.class); AnotherLibrary.doSomething(this); class AnotherLibrary { static void doSomething(Object instance) { Class> cls = instance.getClass(); // ... } }

Slide 16

Slide 16 text

for (Method method : moduleClass.getDeclaredMethods()) { Type returnType = method.getGenericReturnType(); if ((method.getModifiers() & ABSTRACT) != 0) { if (method.getAnnotation(Binds.class) != null) { // ... } else if (method.getAnnotation(BindsOptionalOf.class) != null) { // ... } } else { if ((method.getModifiers() & STATIC) == 0 && instance == null) { // ... } if (method.getAnnotation(Provides.class) != null) { // ... } } }

Slide 17

Slide 17 text

for (Method method : moduleClass.getDeclaredMethods()) { Type returnType = method.getGenericReturnType(); if ((method.getModifiers() & ABSTRACT) != 0) { if (method.getAnnotation(Binds.class) != null) { // ... } else if (method.getAnnotation(BindsOptionalOf.class) != null) { // ... } } else { if ((method.getModifiers() & STATIC) == 0 && instance == null) { // ... } if (method.getAnnotation(Provides.class) != null) { // ... } } }

Slide 18

Slide 18 text

for (Method method : moduleClass.getDeclaredMethods()) { Type returnType = method.getGenericReturnType(); if ((method.getModifiers() & ABSTRACT) != 0) { if (method.getAnnotation(Binds.class) != null) { // ... } else if (method.getAnnotation(BindsOptionalOf.class) != null) { // ... } } else { if ((method.getModifiers() & STATIC) == 0 && instance == null) { // ... } if (method.getAnnotation(Provides.class) != null) { // ... } } }

Slide 19

Slide 19 text

for (Method method : moduleClass.getDeclaredMethods()) { Type returnType = method.getGenericReturnType(); if ((method.getModifiers() & ABSTRACT) != 0) { if (method.getAnnotation(Binds.class) != null) { // ... } else if (method.getAnnotation(BindsOptionalOf.class) != null) { // ... } } else { if ((method.getModifiers() & STATIC) == 0 && instance == null) { // ... } if (method.getAnnotation(Provides.class) != null) { // ... } } }

Slide 20

Slide 20 text

for (Method method : moduleClass.getDeclaredMethods()) { Type returnType = method.getGenericReturnType(); if ((method.getModifiers() & ABSTRACT) != 0) { if (method.getAnnotation(Binds.class) != null) { // ... } else if (method.getAnnotation(BindsOptionalOf.class) != null) { // ... } } else { if ((method.getModifiers() & STATIC) == 0 && instance == null) { // ... } if (method.getAnnotation(Provides.class) != null) { // ... } } }

Slide 21

Slide 21 text

for (Method method : moduleClass.getDeclaredMethods()) { Type returnType = method.getGenericReturnType(); if ((method.getModifiers() & ABSTRACT) != 0) { if (method.getAnnotation(Binds.class) != null) { // ... } else if (method.getAnnotation(BindsOptionalOf.class) != null) { // ... } } else { if ((method.getModifiers() & STATIC) == 0 && instance == null) { // ... } if (method.getAnnotation(Provides.class) != null) { // ... } } }

Slide 22

Slide 22 text

Reflection • Only access to the shape of classes, methods, and fields

Slide 23

Slide 23 text

Reflection • Only access to the shape of classes, methods, and fields • No access to content of methods

Slide 24

Slide 24 text

Reflection • Only access to the shape of classes, methods, and fields • No access to content of methods • Methods can be invoked, fields can be read/written

Slide 25

Slide 25 text

Reflection • Only access to the shape of classes, methods, and fields • No access to content of methods • Methods can be invoked, fields can be read/written • Shape is immutable, no new methods, fields, or types

Slide 26

Slide 26 text

Reflection • Only access to the shape of classes, methods, and fields • No access to content of methods • Methods can be invoked, fields can be read/written • Shape is immutable, no new methods, fields, or types • Annotations can be read from method, field, parameters, and types

Slide 27

Slide 27 text

Reflection • Only access to the shape of classes, methods, and fields • No access to content of methods • Methods can be invoked, fields can be read/written • Shape is immutable, no new methods, fields, or types • Annotations can be read from method, field, parameters, and types • Relatively slow compared to using methods and fields normally

Slide 28

Slide 28 text

public T create(final Class service) { Utils.validateServiceInterface(service); return (T) Proxy.newProxyInstance( service.getClassLoader(), new Class>[] { service }, new InvocationHandler() { @Override public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable { // If the method is from Object then defer to normal invocation. if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); } return loadServiceMethod(method).invoke(args); } }); }

Slide 29

Slide 29 text

public T create(final Class service) { Utils.validateServiceInterface(service); return (T) Proxy.newProxyInstance( service.getClassLoader(), new Class>[] { service }, new InvocationHandler() { @Override public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable { // If the method is from Object then defer to normal invocation. if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); } return loadServiceMethod(method).invoke(args); } }); }

Slide 30

Slide 30 text

public T create(final Class service) { Utils.validateServiceInterface(service); return (T) Proxy.newProxyInstance( service.getClassLoader(), new Class>[] { service }, new InvocationHandler() { @Override public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable { // If the method is from Object then defer to normal invocation. if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); } return loadServiceMethod(method).invoke(args); } }); }

Slide 31

Slide 31 text

public T create(final Class service) { Utils.validateServiceInterface(service); return (T) Proxy.newProxyInstance( service.getClassLoader(), new Class>[] { service }, new InvocationHandler() { @Override public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable { // If the method is from Object then defer to normal invocation. if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); } return loadServiceMethod(method).invoke(args); } }); }

Slide 32

Slide 32 text

public T create(final Class service) { Utils.validateServiceInterface(service); return (T) Proxy.newProxyInstance( service.getClassLoader(), new Class>[] { service }, new InvocationHandler() { @Override public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable { // If the method is from Object then defer to normal invocation. if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); } return loadServiceMethod(method).invoke(args); } }); }

Slide 33

Slide 33 text

public T create(final Class service) { Utils.validateServiceInterface(service); return (T) Proxy.newProxyInstance( service.getClassLoader(), new Class>[] { service }, new InvocationHandler() { @Override public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable { // If the method is from Object then defer to normal invocation. if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); } return loadServiceMethod(method).invoke(args); } }); }

Slide 34

Slide 34 text

Reflection • Only access to the shape of classes, methods, and fields • No access to content of methods • Methods can be invoked, fields can be read/written • Shape is immutable, no new methods, fields, or types • Annotations can be read from method, field, parameters, and types • Relatively slow compared to using methods and fields normally

Slide 35

Slide 35 text

Reflection • Only access to the shape of classes, methods, and fields • No access to content of methods • Methods can be invoked, fields can be read/written • Shape is immutable, no new methods, fields, or types • Annotations can be read from method, field, parameters, and types • Relatively slow compared to using methods and fields normally • Can create implementations of interfaces

Slide 36

Slide 36 text

Reflection • GOOD: Debug tools and testing where performance is less of a concern

Slide 37

Slide 37 text

Reflection • GOOD: Debug tools and testing where performance is less of a concern • GOOD: When dominated by a slower operation like network I/O

Slide 38

Slide 38 text

Reflection • GOOD: Debug tools and testing where performance is less of a concern • GOOD: When dominated by a slower operation like network I/O • OKAY: When on critical path and used infrequently

Slide 39

Slide 39 text

Reflection • GOOD: Debug tools and testing where performance is less of a concern • GOOD: When dominated by a slower operation like network I/O • OKAY: When on critical path and used infrequently • MEH: When used with R8 or ProGuard

Slide 40

Slide 40 text

Reflection • GOOD: Debug tools and testing where performance is less of a concern • GOOD: When dominated by a slower operation like network I/O • OKAY: When on critical path and used infrequently • MEH: When used with R8 or ProGuard • BAD: When on critical path and used heavily

Slide 41

Slide 41 text

Metaprogramming Runtime Compile-time Additive Mutating Reflection / Parser Source generator / Bytecode generator Source transformer / Bytecode transformer

Slide 42

Slide 42 text

Metaprogramming Runtime Compile-time Additive Mutating Reflection / Parser Source generator / Bytecode generator Source transformer / Bytecode transformer

Slide 43

Slide 43 text

SomeLibrary.doSomething(R.raw.stuff);

Slide 44

Slide 44 text

SomeLibrary.doSomething(R.raw.stuff); AnotherLibrary.doSomething("foo.txt");

Slide 45

Slide 45 text

SomeLibrary.doSomething(R.raw.stuff); AnotherLibrary.doSomething("foo.txt"); Response response = // ... Library.doSomething(response.body().string());

Slide 46

Slide 46 text

{"v":"4.8.0","fr":29.9700012207031,"ip":0,"op":61.0000024845809,"w":150,"h":150,"nm":"Name","ddd": 0,"assets":[],"fonts":{"list":[{"origin":0,"fPath":"","fClass":"","fFamily":"Comic Neue","fWeight":"","fStyle":"Regular","fName":"ComicNeue","ascent":69.6990966796875}]},"layers":[{"ddd": 0,"ind":1,"ty":5,"nm":"NAME","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x": 0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":0,"s":[10.5,15,0],"e": [10.5,147,0],"to":[0,22,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y": 0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[10.5,147,0],"e":[10.5,15,0],"to":[0,0,0],"ti":[0,22,0]}, {"t":30.0000012219251}]},"a":{"a":0,"k":[0,0,0]},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y": [0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n": ["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":0,"s": [100,100,100],"e":[196,196,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x": [0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n": ["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":15,"s": [196,196,100],"e":[100,100,100]},{"t":30.0000012219251}]}},"ao":0,"t":{"d":{"k":[{"s":{"s": 14,"f":"ComicNeue","t":"NAME","j":0,"tr":0,"lh":16.8,"ls":0,"fc":[0.92,0,0]},"t":0}]},"p":{},"m":{"g": 1,"a":{"a":0,"k":[0,0]}},"a":[{"s":{"t":0,"xe":{"a":0,"k":0},"ne":{"a":0,"k":0},"a":{"a":0,"k":100},"b": 1,"rn":0,"sh":1,"r":1},"a":{"fc":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y": [0.167]},"n":["0p833_0p833_0p167_0p167"],"t":0,"s":[1,0,0,1],"e":[0,1,0,1]},{"i":{"x":[0.833],"y": [0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":15,"s":[0,1,0,1],"e": [0,0,1,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n": ["0p833_0p833_0p167_0p167"],"t":30,"s":[0,0,1,1],"e":[0,1,0,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x": [0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":45,"s":[0,1,0,1],"e":[1,0,0,1]},{"t": 60.0000024438501}]},"t":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n": ["0p833_0p833_0p167_0p167"],"t":30,"s":[0],"e":[20]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y": [0.167]},"n":["0p833_0p833_0p167_0p167"],"t":45,"s":[20],"e":[0]},{"t":60.0000024438501}]}}}]},"ip": 0,"op":61.0000024845809,"st":0,"bm":0,"sr":1}]}

Slide 47

Slide 47 text

No content

Slide 48

Slide 48 text

• Use any format / schema / language as input Parsing

Slide 49

Slide 49 text

• Use any format / schema / language as input • Be mindful of forward/backward compatibility with inputs Parsing

Slide 50

Slide 50 text

• Use any format / schema / language as input • Be mindful of forward/backward compatibility with inputs • Invoke existing framework APIs or ones from a library Parsing

Slide 51

Slide 51 text

Parsing • GOOD: Re-use output formats from existing tools

Slide 52

Slide 52 text

Parsing • GOOD: Re-use output formats from existing tools • GOOD: Behavior can be loaded from external resource like a server

Slide 53

Slide 53 text

Parsing • GOOD: Re-use output formats from existing tools • GOOD: Behavior can be loaded from external resource like a server • OKAY: When on critical path and used infrequently

Slide 54

Slide 54 text

Parsing • GOOD: Re-use output formats from existing tools • GOOD: Behavior can be loaded from external resource like a server • OKAY: When on critical path and used infrequently • BAD: When on critical path and used heavily

Slide 55

Slide 55 text

Metaprogramming Runtime Compile-time Additive Mutating Reflection / Parser Source generator / Bytecode generator Source transformer / Bytecode transformer

Slide 56

Slide 56 text

Metaprogramming Runtime Compile-time Additive Mutating Reflection / Parser Source generator / Bytecode generator Source transformer / Bytecode transformer

Slide 57

Slide 57 text

message Person { required uint64 id = 1; required string name = 2; optional string email = 3; }

Slide 58

Slide 58 text

message Person { required uint64 id = 1; required string name = 2; optional string email = 3; } class Person { long getId() { .. } String getName() { .. } String getEmail() { .. } class Builder { Builder setId(long id) { .. } Builder setName(String name) { .. } Builder setEmail(String email) { .. } Person build() { .. } } }

Slide 59

Slide 59 text

@AutoValue abstract class Person { static Person from(long id, String name, String email) { return new AutoValue_Person(id, name, email); } abstract long id(); abstract String name(); abstract String email(); }

Slide 60

Slide 60 text

@AutoValue abstract class Person { static Person from(long id, String name, String email) { return new AutoValue_Person(id, name, email); } abstract long id(); abstract String name(); abstract String email(); }

Slide 61

Slide 61 text

@AutoValue abstract class Person { static Person from(long id, String name, String email) { return new AutoValue_Person(id, name, email); } abstract long id(); abstract String name(); abstract String email(); }

Slide 62

Slide 62 text

@AutoValue abstract class Person { static Person from(long id, String name, String email) { return new AutoValue_Person(id, name, email); } abstract long id(); abstract String name(); abstract String email(); }

Slide 63

Slide 63 text

@AutoValue abstract class Person { static Person from(long id, String name, String email) { return new AutoValue_Person(id, name, email); } abstract long id(); abstract String name(); abstract String email(); } final class AutoValue_Person extends Person { AutoValue_Person(long id, String name, String email) { .. } @Override abstract long id() { .. } @Override abstract String name() { .. } @Override abstract String email() { .. } // equals(), hashCode(), toString()... }

Slide 64

Slide 64 text

• Only access to the shape of classes, methods, and fields Source Generator (Annotation Processor)

Slide 65

Slide 65 text

• Only access to the shape of classes, methods, and fields • No access to content of methods Source Generator (Annotation Processor)

Slide 66

Slide 66 text

• Only access to the shape of classes, methods, and fields • No access to content of methods • Shape of existing code is immutable, no new methods, fields, or types Source Generator (Annotation Processor)

Slide 67

Slide 67 text

• Only access to the shape of classes, methods, and fields • No access to content of methods • Shape of existing code is immutable, no new methods, fields, or types • Annotations can be read from method, field, parameters, and types Source Generator (Annotation Processor)

Slide 68

Slide 68 text

• Only access to the shape of classes, methods, and fields • No access to content of methods • Shape of existing code is immutable, no new methods, fields, or types • Annotations can be read from method, field, parameters, and types • Can generate any kind of type or a Java resource Source Generator (Annotation Processor)

Slide 69

Slide 69 text

• Only access to the shape of classes, methods, and fields • No access to content of methods • Shape of existing code is immutable, no new methods, fields, or types • Annotations can be read from method, field, parameters, and types • Can generate any kind of type or a Java resource • Avoid leaking generated code into API, treat as implementation detail Source Generator (Annotation Processor)

Slide 70

Slide 70 text

• Only access to the shape of classes, methods, and fields • No access to content of methods • Shape of existing code is immutable, no new methods, fields, or types • Annotations can be read from method, field, parameters, and types • Can generate any kind of type or a Java resource • Avoid leaking generated code into API, treat as implementation detail • Use JavaPoet, KotlinPoet, auto-common, and/or compile-testing to build Source Generator (Annotation Processor)

Slide 71

Slide 71 text

• Generated source code can be public API and should feel like a library Source Generator (Other)

Slide 72

Slide 72 text

• Generated source code can be public API and should feel like a library • You can generate inputs to other tools like ProGuard rules or drawable XML Source Generator (Other)

Slide 73

Slide 73 text

• Generated source code can be public API and should feel like a library • You can generate inputs to other tools like ProGuard rules or drawable XML • Use JavaPoet and KotlinPoet for source generation Source Generator (Other)

Slide 74

Slide 74 text

• GOOD: Same performance and capability as hand-written code Source Generator

Slide 75

Slide 75 text

• GOOD: Same performance and capability as hand-written code • GOOD: Relatively easy to create and change Source Generator

Slide 76

Slide 76 text

• GOOD: Same performance and capability as hand-written code • GOOD: Relatively easy to create and change • GOOD: Works extremely well with R8 and ProGuard Source Generator

Slide 77

Slide 77 text

• GOOD: Same performance and capability as hand-written code • GOOD: Relatively easy to create and change • GOOD: Works extremely well with R8 and ProGuard • OKAY: Can contribute a lot of methods, fields, and allocations Source Generator

Slide 78

Slide 78 text

• GOOD: Same performance and capability as hand-written code • GOOD: Relatively easy to create and change • GOOD: Works extremely well with R8 and ProGuard • OKAY: Can contribute a lot of methods, fields, and allocations • MEH: Referencing generated code from annotation processors Source Generator

Slide 79

Slide 79 text

• GOOD: Same performance and capability as hand-written code • GOOD: Relatively easy to create and change • GOOD: Works extremely well with R8 and ProGuard • OKAY: Can contribute a lot of methods, fields, and allocations • MEH: Referencing generated code from annotation processors • MEH: Build performance impact requires care Source Generator

Slide 80

Slide 80 text

Metaprogramming Runtime Compile-time Additive Mutating Reflection / Parser Source generator / Bytecode generator Source transformer / Bytecode transformer

Slide 81

Slide 81 text

Metaprogramming Runtime Compile-time Additive Mutating Reflection / Parser Source generator / Bytecode generator Source transformer / Bytecode transformer

Slide 82

Slide 82 text

// search_item.xml

Slide 83

Slide 83 text

// search_item.xml

Slide 84

Slide 84 text

// search_item.xml final class R { static final class id { static final int class_name = 0x7f0000001; static final int more_options = 0x7f000002; static final int package_name = 0x7f000003; } static final class layout { static final int search_item = 0x7f000004; } }

Slide 85

Slide 85 text

// search_item.xml $ find build -name 'R.*' build/intermediates/r_class_jar/release/generateReleaseRFile/R.jar build/intermediates/r_class_jar/debug/generateDebugRFile/R.jar

Slide 86

Slide 86 text

// search_item.xml $ find build -name 'R.*' build/intermediates/r_class_jar/release/generateReleaseRFile/R.jar build/intermediates/r_class_jar/debug/generateDebugRFile/R.jar $ javap -cp build/.../generateReleaseRFile/R.jar 'com.example.R$layout' public final class com.jakewharton.sdksearch.search.ui.R$layout { public static final int class_name; public static final int more_options; public static final int package_name; }

Slide 87

Slide 87 text

Bytecode Generator • Same basic guidelines as source generation

Slide 88

Slide 88 text

Bytecode Generator • Same basic guidelines as source generation • Use ASM or ByteBuddy, or some kind of IR

Slide 89

Slide 89 text

Bytecode Generator • GOOD: Same or better performance and capability as hand-written code

Slide 90

Slide 90 text

Bytecode Generator • GOOD: Same or better performance and capability as hand-written code • GOOD: Works extremely well with R8 and ProGuard

Slide 91

Slide 91 text

Bytecode Generator • GOOD: Same or better performance and capability as hand-written code • GOOD: Works extremely well with R8 and ProGuard • GOOD: Avoids the need to run Java and Kotlin compiler

Slide 92

Slide 92 text

Bytecode Generator • GOOD: Same or better performance and capability as hand-written code • GOOD: Works extremely well with R8 and ProGuard • GOOD: Avoids the need to run Java and Kotlin compiler • MEH: Somewhat hard to write and maintain

Slide 93

Slide 93 text

Bytecode Generator • GOOD: Same or better performance and capability as hand-written code • GOOD: Works extremely well with R8 and ProGuard • GOOD: Avoids the need to run Java and Kotlin compiler • MEH: Somewhat hard to write and maintain • BAD: No source code to step through while debugging

Slide 94

Slide 94 text

Metaprogramming Runtime Compile-time Additive Mutating Reflection / Parser Source generator / Bytecode generator Source transformer / Bytecode transformer

Slide 95

Slide 95 text

Metaprogramming Runtime Compile-time Additive Mutating Reflection / Parser Source generator / Bytecode generator Source transformer / Bytecode transformer

Slide 96

Slide 96 text

class TimedRunnable implements Comparable { final long execTime; @Override public int compareTo(TimedRunnable that) { return Long.compare(execTime, that.execTime); } }

Slide 97

Slide 97 text

class TimedRunnable implements Comparable { final long execTime; @Override public int compareTo(TimedRunnable that) { return Long.compare(execTime, that.execTime); } }

Slide 98

Slide 98 text

class TimedRunnable implements Comparable { final long execTime; @Override public int compareTo(TimedRunnable that) { return Long.compare(execTime, that.execTime); } } java/lang/Long.compare --> io/reactivex/internal/java/lang/Long.compare

Slide 99

Slide 99 text

class TimedRunnable implements Comparable { final long execTime; @Override public int compareTo(TimedRunnable that) { return Long.compare(execTime, that.execTime); } } java/lang/Long.compare --> io/reactivex/internal/java/lang/Long.compare class TimedRunnable implements Comparable { final long execTime; @Override public int compareTo(TimedRunnable that) { return io.reactivex.internal.java.lang.Long.compare( execTime, that.execTime); } }

Slide 100

Slide 100 text

Source Transformer • Unlike annotation processing, you have access to method body content

Slide 101

Slide 101 text

Source Transformer • Unlike annotation processing, you have access to method body content • Free to change, update, and delete any types, method, fields, and code

Slide 102

Slide 102 text

Source Transformer • Unlike annotation processing, you have access to method body content • Free to change, update, and delete any types, method, fields, and code • Use Spoon for complicated transformations, regex for simple ones

Slide 103

Slide 103 text

Source Transformer • GOOD: Can be as simple or complex as needed

Slide 104

Slide 104 text

Source Transformer • GOOD: Can be as simple or complex as needed • GOOD: Easy to get started and experiment with

Slide 105

Slide 105 text

Source Transformer • GOOD: Can be as simple or complex as needed • GOOD: Easy to get started and experiment with • MEH: Limited applicability

Slide 106

Slide 106 text

Source Transformer • GOOD: Can be as simple or complex as needed • GOOD: Easy to get started and experiment with • MEH: Limited applicability • BAD: Transformations are brittle and prone to breakage

Slide 107

Slide 107 text

Metaprogramming Runtime Compile-time Additive Mutating Reflection / Parser Source generator / Bytecode generator Source transformer / Bytecode transformer

Slide 108

Slide 108 text

Metaprogramming Runtime Compile-time Additive Mutating Reflection / Parser Source generator / Bytecode generator Source transformer / Bytecode transformer

Slide 109

Slide 109 text

$ javap -c build/classes/main/io/reactivex/internal/schedulers/TrampolineScheduler\$TimedRunnable.class Compiled from "TrampolineScheduler.java" final class io.reactivex.internal.schedulers.TrampolineScheduler$TimedRunnable implements java.lang.Comparable { final java.lang.Runnable run; final long execTime; public int compareTo(io.reactivex.internal.schedulers.TrampolineScheduler$TimedRunnable); Code: 0: aload_0 1: getfield #5 // Field execTime:J 4: aload_1 5: getfield #5 // Field execTime:J 8: invokestatic #7 // Method java/lang/Long.compare:(JJ)I 11: ireturn }

Slide 110

Slide 110 text

$ javap -c build/classes/main/io/reactivex/internal/schedulers/TrampolineScheduler\$TimedRunnable.class Compiled from "TrampolineScheduler.java" final class io.reactivex.internal.schedulers.TrampolineScheduler$TimedRunnable implements java.lang.Comparable { final java.lang.Runnable run; final long execTime; public int compareTo(io.reactivex.internal.schedulers.TrampolineScheduler$TimedRunnable); Code: 0: aload_0 1: getfield #5 // Field execTime:J 4: aload_1 5: getfield #5 // Field execTime:J 8: invokestatic #7 // Method java/lang/Long.compare:(JJ)I 11: ireturn }

Slide 111

Slide 111 text

final class BackportingMethodCallRemapper extends ClassVisitor { BackportingMethodCallRemapper(ClassVisitor cv) { super(ASM5, cv); } @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); if (mv == null) { return null; } return new MethodVisitor(ASM5, mv) { @Override public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { if ("java/lang/Long".equals(owner) && "compare".equals(name)) { owner = "io/reactivex/internal/java/lang/Long"; } super.visitMethodInsn(opcode, owner, name, desc, itf); } }; } }

Slide 112

Slide 112 text

final class BackportingMethodCallRemapper extends ClassVisitor { BackportingMethodCallRemapper(ClassVisitor cv) { super(ASM5, cv); } @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); if (mv == null) { return null; } return new MethodVisitor(ASM5, mv) { @Override public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { if ("java/lang/Long".equals(owner) && "compare".equals(name)) { owner = "io/reactivex/internal/java/lang/Long"; } super.visitMethodInsn(opcode, owner, name, desc, itf); } }; } }

Slide 113

Slide 113 text

$ javap -c build/classes/main/io/reactivex/internal/schedulers/TrampolineScheduler\$TimedRunnable.class Compiled from "TrampolineScheduler.java" final class io.reactivex.internal.schedulers.TrampolineScheduler$TimedRunnable implements java.lang.Comparable { final java.lang.Runnable run; final long execTime; public int compareTo(io.reactivex.internal.schedulers.TrampolineScheduler$TimedRunnable); Code: 0: aload_0 1: getfield #5 // Field execTime:J 4: aload_1 5: getfield #5 // Field execTime:J 8: invokestatic #7 // Method io/reactivex/internal/java/lang/Long.compare:(JJ)I 11: ireturn }

Slide 114

Slide 114 text

$ javap -c build/classes/main/io/reactivex/internal/schedulers/TrampolineScheduler\$TimedRunnable.class Compiled from "TrampolineScheduler.java" final class io.reactivex.internal.schedulers.TrampolineScheduler$TimedRunnable implements java.lang.Comparable { final java.lang.Runnable run; final long execTime; public int compareTo(io.reactivex.internal.schedulers.TrampolineScheduler$TimedRunnable); Code: 0: aload_0 1: getfield #5 // Field execTime:J 4: aload_1 5: getfield #5 // Field execTime:J 8: invokestatic #7 // Method io/reactivex/internal/java/lang/Long.compare:(JJ)I 11: ireturn }

Slide 115

Slide 115 text

public static void main(String... args) { sayHi(s -> System.out.println(s)); }

Slide 116

Slide 116 text

public static void main(String... args) { sayHi(s -> System.out.println(s)); } BootstrapMethods: 0: #27 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:( Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String; Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType; Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/ MethodType;) Ljava/lang/invoke/CallSite; Method arguments: #28 (Ljava/lang/String;)V #29 invokestatic Java8.lambda$main$0:(Ljava/lang/String;)V #28 (Ljava/lang/String;)V

Slide 117

Slide 117 text

public static void main(String... args) { sayHi(s -> System.out.println(s)); } [0002bc] Java8.main:([Ljava/lang/String;)V 0000: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; 0003: new-instance v0, L-$$Lambda$1Osqr2Z9OSwjseX_0FMQJcCG_uM; 0004: invoke-direct {v0, v1}, L-$$Lambda$1Osqr2Z9OSwjseX_0FMQJcCG_uM;.: (Ljava/io/PrintStream;)V 0008: invoke-static {v0}, LJava8;.sayHi:(LJava8$Logger;)V

Slide 118

Slide 118 text

Bytecode Transformer • Free to change, update, and delete any types, method, fields, and code

Slide 119

Slide 119 text

Bytecode Transformer • Free to change, update, and delete any types, method, fields, and code • Create constructs which cannot be represented in source

Slide 120

Slide 120 text

Bytecode Transformer • Free to change, update, and delete any types, method, fields, and code • Create constructs which cannot be represented in source • Use ASM or ByteBuddy, or some kind of IR

Slide 121

Slide 121 text

Bytecode Transformer • GOOD: Unlimited power to create, modify, and delete anything as desired

Slide 122

Slide 122 text

Bytecode Transformer • GOOD: Unlimited power to create, modify, and delete anything as desired • OKAY: Build system integration not always easy

Slide 123

Slide 123 text

Bytecode Transformer • GOOD: Unlimited power to create, modify, and delete anything as desired • OKAY: Build system integration not always easy • OKAY: Can affect debugging and stacktraces in non-obvious ways

Slide 124

Slide 124 text

Bytecode Transformer • GOOD: Unlimited power to create, modify, and delete anything as desired • OKAY: Build system integration not always easy • OKAY: Can affect debugging and stacktraces in non-obvious ways • MEH: Requires a lot of machinery and knowledge of bytecode

Slide 125

Slide 125 text

Metaprogramming Runtime Compile-time Additive Mutating Reflection / Parser Source generator / Bytecode generator Source transformer / Bytecode transformer

Slide 126

Slide 126 text

Metaprogramming Runtime Compile-time Additive Mutating Reflection / Parser Source generator / Bytecode generator Source transformer / Bytecode transformer

Slide 127

Slide 127 text

Network Requests

Slide 128

Slide 128 text

GET /users HTTP/1.1 [{id:1,name:"Jake"}]

Slide 129

Slide 129 text

[{id:1,name:"Jake"}] GET /users HTTP/1.1

Slide 130

Slide 130 text

[{id:1,name:"Jake"}] GET /users HTTP/1.1

Slide 131

Slide 131 text

interface GitHubService { suspend fun users(): List }X data class User( val id: Long, val login: String )Y

Slide 132

Slide 132 text

interface GitHubService { @GET("/users") suspend fun users(): List }X data class User( val id: Long, val login: String )Y

Slide 133

Slide 133 text

interface GitHubService { @GET("/users") suspend fun users(): List }X @JsonClass data class User( val id: Long, val login: String )Y

Slide 134

Slide 134 text

interface GitHubService { @GET("/users") suspend fun users(): List }X @JsonClass data class User( val id: Long, val login: String )Y

Slide 135

Slide 135 text

interface GitHubService { @GET("/users") suspend fun users(): List }X @JsonClass data class User( val id: Long, val login: String )Y

Slide 136

Slide 136 text

GET /users HTTP/1.1 [{id:1,name:"Jake"}]

Slide 137

Slide 137 text

GET /users HTTP/1.1 [{id:1,name:"Jake"}]

Slide 138

Slide 138 text

interface GitHubService { @GET("/users") suspend fun users(): List }X @JsonClass data class User( val id: Long, val login: String )Y

Slide 139

Slide 139 text

interface GitHubService { @GET("/users") suspend fun users(): List }X @JsonClass data class User( val id: Long, val login: String )Y

Slide 140

Slide 140 text

GET /users HTTP/1.1 [{id:1,name:"Jake"}] interface GitHubService { @GET("/users") suspend fun users(): List }X @JsonClass data class User( val id: Long, val login: String )Y

Slide 141

Slide 141 text

interface GitHubService {A @GET("/users") suspend fun users(): List }X

Slide 142

Slide 142 text

class GitHubService(val client: OkHttpClient) {A suspend fun users(): List { // ... }B }X i n t e r f a c e @GET("/users")

Slide 143

Slide 143 text

Android Layouts

Slide 144

Slide 144 text

// search_item.xml

Slide 145

Slide 145 text

class SearchItemActivity extends Activity { private TextView packageNameView; private TextView classNameView; private ImageButton moreOptionsView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.search_item); packageNameView = findViewById(R.id.package_name); classNameView = findViewById(R.id.class_name); moreOptionsView = findViewById(R.id.more_options); }B void later() { packageName.setText("com.example"); className.setText("ExampleClass"); moreOptions.setImageResource(R.drawable.view_source); }B }A

Slide 146

Slide 146 text

private private private packageNameView = findViewById( ); classNameView = findViewById( ); moreOptionsView = findViewById( ); class SearchItemActivity extends Activity { @BindView(R.id.package_name) TextView packageNameView; @BindView(R.id.class_name) TextView classNameView; @BindView(R.id.more_options) ImageButton moreOptionsView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.search_item); ButterKnife.bind(this); }B void later() { packageName.setText("com.example"); className.setText("ExampleClass"); moreOptions.setImageResource(R.drawable.view_source); }B }A

Slide 147

Slide 147 text

class SearchItemActivity : Activity { @Override fun onCreate(savedInstanceState: Bundle) { super.onCreate(savedInstanceState) setContentView(R.layout.search_item) }B fun later() { packageName.text = "com.example" className.text = "ExampleClass" moreOptions.setImageResource(R.drawable.view_source) }B }A e x t e n d s @BindView(R.id.package_name) TextView packageNameView; @BindView(R.id.class_name) TextView classNameView; @BindView(R.id.more_options) ImageButton moreOptionsView; protected void ButterKnife.bind(this); void setText( ); setText( );

Slide 148

Slide 148 text

// search_item.xml

Slide 149

Slide 149 text

// search_item.xml 1. Layout file name

Slide 150

Slide 150 text

// search_item.xml 1. Layout file name 2. Root view type

Slide 151

Slide 151 text

// search_item.xml 1. Layout file name 2. Root view type 3. Type of each view with ID

Slide 152

Slide 152 text

// search_item.xml 1. Layout file name 2. Root view type 3. Type of each view with ID 4. Which IDs are contained
 inside each layout

Slide 153

Slide 153 text

// search_item.xml 1. Layout file name 2. Root view type 3. Type of each view with ID 4. Which IDs are contained
 inside each layout 5. Whether an ID is present in
 every layout configuration

Slide 154

Slide 154 text

class SearchItemActivity extends Activity { private TextView packageNameView; private TextView classNameView; private ImageButton moreOptionsView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.search_item); packageNameView = findViewById(R.id.package_name); classNameView = findViewById(R.id.class_name); moreOptionsView = findViewById(R.id.more_options); }B void later() { packageName.setText("com.example"); className.setText("ExampleClass"); moreOptions.setImageResource(R.drawable.view_source); } }A 1. Layout file name 2. Root view type 3. Type of each view with ID 4. Which IDs are contained
 inside each layout 5. Whether an ID is present in
 every layout configuration

Slide 155

Slide 155 text

class SearchItemActivity extends Activity { private TextView packageNameView; private TextView classNameView; private ImageButton moreOptionsView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.search_item); packageNameView = findViewById(R.id.package_name); classNameView = findViewById(R.id.class_name); moreOptionsView = findViewById(R.id.more_options); }B void later() { packageName.setText("com.example"); className.setText("ExampleClass"); moreOptions.setImageResource(R.drawable.view_source); } }A 1. Layout file name 2. Root view type 3. Type of each view with ID 4. Which IDs are contained
 inside each layout 5. Whether an ID is present in
 every layout configuration

Slide 156

Slide 156 text

class SearchItemActivity extends Activity { private TextView packageNameView; private TextView classNameView; private ImageButton moreOptionsView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.search_item); packageNameView = findViewById(R.id.package_name); classNameView = findViewById(R.id.class_name); moreOptionsView = findViewById(R.id.more_options); }B void later() { packageName.setText("com.example"); className.setText("ExampleClass"); moreOptions.setImageResource(R.drawable.view_source); } }A 1. Layout file name 3. Type of each view with ID 4. Which IDs are contained
 inside each layout 5. Whether an ID is present in
 every layout configuration 2. Root view type

Slide 157

Slide 157 text

class SearchItemActivity extends Activity { private TextView packageNameView; private TextView classNameView; private ImageButton moreOptionsView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.search_item); packageNameView = findViewById(R.id.package_name); classNameView = findViewById(R.id.class_name); moreOptionsView = findViewById(R.id.more_options); }B void later() { packageName.setText("com.example"); className.setText("ExampleClass"); moreOptions.setImageResource(R.drawable.view_source); } }A 1. Layout file name 4. Which IDs are contained
 inside each layout 5. Whether an ID is present in
 every layout configuration 2. Root view type 3. Type of each view with ID

Slide 158

Slide 158 text

class SearchItemActivity extends Activity { private TextView packageNameView; private TextView classNameView; private ImageButton moreOptionsView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.search_item); packageNameView = findViewById(R.id.package_name); classNameView = findViewById(R.id.class_name); moreOptionsView = findViewById(R.id.more_options); }B void later() { packageName.setText("com.example"); className.setText("ExampleClass"); moreOptions.setImageResource(R.drawable.view_source); } }A 1. Layout file name 5. Whether an ID is present in
 every layout configuration 2. Root view type 3. Type of each view with ID 4. Which IDs are contained
 inside each layout

Slide 159

Slide 159 text

class SearchItemActivity extends Activity { private TextView packageNameView; private TextView classNameView; private ImageButton moreOptionsView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.search_item); packageNameView = findViewById(R.id.package_name); classNameView = findViewById(R.id.class_name); moreOptionsView = findViewById(R.id.more_options); }B void later() { packageName.setText("com.example"); className.setText("ExampleClass"); moreOptions.setImageResource(R.drawable.view_source); } }A 1. Layout file name 2. Root view type 3. Type of each view with ID 4. Which IDs are contained
 inside each layout 5. Whether an ID is present in
 every layout configuration

Slide 160

Slide 160 text

class SearchItemActivity extends Activity { @BindView(R.id.package_name) TextView packageNameView; @BindView(R.id.class_name) TextView classNameView; @BindView(R.id.more_options) ImageButton moreOptionsView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.search_item); ButterKnife.bind(this); }B void later() { packageName.setText("com.example"); className.setText("ExampleClass"); moreOptions.setImageResource(R.drawable.view_source); } }A 1. Layout file name 2. Root view type 3. Type of each view with ID 4. Which IDs are contained
 inside each layout 5. Whether an ID is present in
 every layout configuration

Slide 161

Slide 161 text

class SearchItemActivity extends Activity { @BindView(R.id.package_name) TextView packageNameView; @BindView(R.id.class_name) TextView classNameView; @BindView(R.id.more_options) ImageButton moreOptionsView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.search_item); ButterKnife.bind(this); }B void later() { packageName.setText("com.example"); className.setText("ExampleClass"); moreOptions.setImageResource(R.drawable.view_source); } }A 1. Layout file name 2. Root view type 3. Type of each view with ID 4. Which IDs are contained
 inside each layout 5. Whether an ID is present in
 every layout configuration

Slide 162

Slide 162 text

class SearchItemActivity extends Activity { @BindView(R.id.package_name) TextView packageNameView; @BindView(R.id.class_name) TextView classNameView; @BindView(R.id.more_options) ImageButton moreOptionsView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.search_item); ButterKnife.bind(this); }B void later() { packageName.setText("com.example"); className.setText("ExampleClass"); moreOptions.setImageResource(R.drawable.view_source); } }A 1. Layout file name 2. Root view type 3. Type of each view with ID 4. Which IDs are contained
 inside each layout 5. Whether an ID is present in
 every layout configuration

Slide 163

Slide 163 text

class SearchItemActivity extends Activity { @BindView(R.id.package_name) TextView packageNameView; @BindView(R.id.class_name) TextView classNameView; @BindView(R.id.more_options) ImageButton moreOptionsView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.search_item); ButterKnife.bind(this); }B void later() { packageName.setText("com.example"); className.setText("ExampleClass"); moreOptions.setImageResource(R.drawable.view_source); } }A 1. Layout file name 2. Root view type 3. Type of each view with ID 4. Which IDs are contained
 inside each layout 5. Whether an ID is present in
 every layout configuration

Slide 164

Slide 164 text

class SearchItemActivity extends Activity { @BindView(R.id.package_name) TextView packageNameView; @BindView(R.id.class_name) TextView classNameView; @BindView(R.id.more_options) ImageButton moreOptionsView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.search_item); ButterKnife.bind(this); }B void later() { packageName.setText("com.example"); className.setText("ExampleClass"); moreOptions.setImageResource(R.drawable.view_source); } }A 1. Layout file name 2. Root view type 3. Type of each view with ID 4. Which IDs are contained
 inside each layout 5. Whether an ID is present in
 every layout configuration

Slide 165

Slide 165 text

class SearchItemActivity extends Activity { @BindView(R.id.package_name) TextView packageNameView; @BindView(R.id.class_name) TextView classNameView; @BindView(R.id.more_options) ImageButton moreOptionsView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.search_item); ButterKnife.bind(this); }B void later() { packageName.setText("com.example"); className.setText("ExampleClass"); moreOptions.setImageResource(R.drawable.view_source); } }A 1. Layout file name 2. Root view type 3. Type of each view with ID 4. Which IDs are contained
 inside each layout 5. Whether an ID is present in
 every layout configuration

Slide 166

Slide 166 text

class SearchItemActivity : Activity { @Override fun onCreate(savedInstanceState: Bundle) { super.onCreate(savedInstanceState) setContentView(R.layout.search_item) }B fun later() { packageName.text = "com.example" className.text = "ExampleClass" moreOptions.setImageResource(R.drawable.view_source) } }A 1. Layout file name 2. Root view type 3. Type of each view with ID 4. Which IDs are contained
 inside each layout 5. Whether an ID is present in
 every layout configuration

Slide 167

Slide 167 text

class SearchItemActivity : Activity { @Override fun onCreate(savedInstanceState: Bundle) { super.onCreate(savedInstanceState) setContentView(R.layout.search_item) }B fun later() { packageName.text = "com.example" className.text = "ExampleClass" moreOptions.setImageResource(R.drawable.view_source) } }A 1. Layout file name 2. Root view type 3. Type of each view with ID 4. Which IDs are contained
 inside each layout 5. Whether an ID is present in
 every layout configuration

Slide 168

Slide 168 text

class SearchItemActivity : Activity { @Override fun onCreate(savedInstanceState: Bundle) { super.onCreate(savedInstanceState) setContentView(R.layout.search_item) }B fun later() { packageName.text = "com.example" className.text = "ExampleClass" moreOptions.setImageResource(R.drawable.view_source) } }A 1. Layout file name 2. Root view type 3. Type of each view with ID 4. Which IDs are contained
 inside each layout 5. Whether an ID is present in
 every layout configuration

Slide 169

Slide 169 text

class SearchItemActivity : Activity { @Override fun onCreate(savedInstanceState: Bundle) { super.onCreate(savedInstanceState) setContentView(R.layout.search_item) }B fun later() { packageName.text = "com.example" className.text = "ExampleClass" moreOptions.setImageResource(R.drawable.view_source) } }A 1. Layout file name 2. Root view type 3. Type of each view with ID 4. Which IDs are contained
 inside each layout 5. Whether an ID is present in
 every layout configuration

Slide 170

Slide 170 text

class SearchItemActivity : Activity { @Override fun onCreate(savedInstanceState: Bundle) { super.onCreate(savedInstanceState) setContentView(R.layout.search_item) }B fun later() { packageName.text = "com.example" className.text = "ExampleClass" moreOptions.setImageResource(R.drawable.view_source) } }A 1. Layout file name 2. Root view type 3. Type of each view with ID 4. Which IDs are contained
 inside each layout 5. Whether an ID is present in
 every layout configuration 6. Kotlin-only

Slide 171

Slide 171 text

class SearchItemActivity extends Activity { private SearchItemBinding layout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); layout = setContentView(this, R.layout.search_item); }B void later() { layout.packageName.setText("com.example"); layout.className.setText("ExampleClass"); layout.moreOptions.setImageResource(R.drawable.view_source); } }A 1. Layout file name 3. Type of each view with ID 4. Which IDs are contained
 inside each layout 5. Whether an ID is present in
 every layout configuration 2. Root view type

Slide 172

Slide 172 text

class SearchItemActivity extends Activity { private SearchItemBinding layout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); layout = setContentView(this, R.layout.search_item); }B void later() { layout.packageName.setText("com.example"); layout.className.setText("ExampleClass"); layout.moreOptions.setImageResource(R.drawable.view_source); } }A 1. Layout file name 2. Root view type 3. Type of each view with ID 4. Which IDs are contained
 inside each layout 5. Whether an ID is present in
 every layout configuration

Slide 173

Slide 173 text

// search_item.xml

Slide 174

Slide 174 text

// search_item.xml

Slide 175

Slide 175 text

// search_item.xml Android Gradle plugin

Slide 176

Slide 176 text

// search_item.xml Android Gradle plugin class SearchItemBinding { public final TextView packageName; public final TextView className; public final ImageButton moreOptions; }A

Slide 177

Slide 177 text

// search_item.xml Android Gradle plugin @Binding class SearchItemBinding { public final TextView packageName; public final TextView className; public final ImageButton moreOptions; }A

Slide 178

Slide 178 text

// search_item.xml Android Gradle plugin annotationProcessor 'androidx.databinding:databinding-compiler:3.4.0' @Binding class SearchItemBinding { public final TextView packageName; public final TextView className; public final ImageButton moreOptions; }A

Slide 179

Slide 179 text

// search_item.xml Android Gradle plugin Java compiler annotationProcessor 'androidx.databinding:databinding-compiler:3.4.0' @Binding class SearchItemBinding { public final TextView packageName; public final TextView className; public final ImageButton moreOptions; }A

Slide 180

Slide 180 text

// search_item.xml Android Gradle plugin Java compiler annotationProcessor 'androidx.databinding:databinding-compiler:3.4.0' @Binding class SearchItemBinding { public final TextView packageName; public final TextView className; public final ImageButton moreOptions; }A class SearchItemBindingImpl extends SearchItemBinding { // ... }A

Slide 181

Slide 181 text

// search_item.xml Android Gradle plugin Java compiler annotationProcessor 'androidx.databinding:databinding-compiler:3.4.0' @Binding class SearchItemBinding { public final TextView packageName; public final TextView className; public final ImageButton moreOptions; }A class SearchItemBindingImpl extends SearchItemBinding { // ... }A

Slide 182

Slide 182 text

// search_item.xml Android Gradle plugin Java compiler annotationProcessor 'androidx.databinding:databinding-compiler:3.4.0' @Binding class SearchItemBinding { public final TextView packageName; public final TextView className; public final ImageButton moreOptions; }A class SearchItemBindingImpl extends SearchItemBinding { // ... }A

Slide 183

Slide 183 text

// search_item.xml Android Gradle plugin Java compiler annotationProcessor 'androidx.databinding:databinding-compiler:3.4.0' @Binding class SearchItemBinding { public final TextView packageName; public final TextView className; public final ImageButton moreOptions; }A class SearchItemBindingImpl extends SearchItemBinding { // ... }A

Slide 184

Slide 184 text

class SearchItemActivity extends Activity { private SearchItemBinding layout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); layout = SearchItemBinding.inflate(this); setContentView(layout); }B void later() { layout.packageName.setText("com.example"); layout.className.setText("ExampleClass"); layout.moreOptions.setImageResource(R.drawable.view_source); } }A 1. Layout file name 2. Root view type 3. Type of each view with ID 4. Which IDs are contained
 inside each layout 5. Whether an ID is present in
 every layout configuration

Slide 185

Slide 185 text

class SearchItemActivity extends Activity { private SearchItemBinding layout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); layout = SearchItemBinding.inflate(this); setContentView(layout); }B void later() { layout.packageName.setText("com.example"); layout.className.setText("ExampleClass"); layout.moreOptions.setImageResource(R.drawable.view_source); } }A (HINT)

Slide 186

Slide 186 text

Database Queries

Slide 187

Slide 187 text

CREATE TABLE user( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, email TEXT NOT NULL ); SELECT email FROM user WHERE name LIKE 'Jake %'

Slide 188

Slide 188 text

@Table("user") class User { @PrimaryKey @AutoIncrement long id; @NotNull String name; @NotNull String email; }A Database db = Database.create(context, User.class, ..); List jakes = db.from(User.class) .where("name", like("Jake %")) .select("email") .toList(String.class);

Slide 189

Slide 189 text

Table @A Increment Database db = Database.create(context, User.class, ..); List jakes = db.from(User.class) .where("name", like("Jake %")) .select("email") .toList(String.class); @Entity(tableName = "user") class User { @PrimaryKey(autoGenerate = true) long id; @NotNull String name; @NotNull String email; }A @Dao interface UserDao { @Query("SELECT email FROM user WHERE name LIKE 'JAKE %'") List jakes(); }H

Slide 190

Slide 190 text

@Entity(tableName = "user") class User { @PrimaryKey(autoGenerate = true) long id; @NotNull String name; @NotNull String email; }A @Dao interface UserDao { @Query("SELECT email FROM user WHERE name LIKE 'JAKE %'") List jakes(); }H

Slide 191

Slide 191 text

@Entity(tableName = "user") class User { @PrimaryKey(autoGenerate = true) long id; @NotNull String name; @NotNull String email; }A @Dao interface UserDao { @Query("SELECT name, email FROM user WHERE name LIKE 'JAKE %'") List??> jakes(); }H S t r i n g User

Slide 192

Slide 192 text

@Entity(tableName = "user") class User { @PrimaryKey(autoGenerate = true) long id; @NotNullA String name; @NotNullB String email; }A @Dao interface UserDao { @Query("SELECT * FROM user WHERE name LIKE 'JAKE %'") List jakes(); }H

Slide 193

Slide 193 text

@Entity(tableName = "user") class User { @PrimaryKey(autoGenerate = true) long id; @NotNullAString name; @NotNullBString email; @Nullable LocalDate birthday; @NonNull LocalDate created; boolean is_admin; @Nullable String home_address; @Nullable String phone_number; }A @Dao interface UserDao { @Query("SELECT * FROM user WHERE name LIKE 'JAKE %'") List jakes(); }H

Slide 194

Slide 194 text

CREATE TABLE user( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, email TEXT NOT NULL ); SELECT name, email FROM user WHERE name LIKE 'Jake %'

Slide 195

Slide 195 text

CREATE TABLE user( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, email TEXT NOT NULL ); SELECT name, email FROM user WHERE name LIKE 'Jake %' data class User( val id: Long, val name: String, val email: String ) data class JakeResult( val name: String, val email: String ) interface UserQueries { fun jakes(): Query }

Slide 196

Slide 196 text

Mechanisms of Metaprogramming @JakeWharton