annotation processing in android

36
ANNOTATION PROCESSING IN ANDROID Emanuele Zattin - Realm @emanuelez 19-2-2016 - DroidKaigi

Upload: emanuelez

Post on 19-Jan-2017

2.796 views

Category:

Software


1 download

TRANSCRIPT

Page 1: Annotation Processing in Android

ANNOTATION PROCESSING

IN ANDROIDEmanuele Zattin - Realm

@emanuelez

19-2-2016 - DroidKaigi

Page 2: Annotation Processing in Android

DroidKaigi

Page 3: Annotation Processing in Android

WHAT IS A JAVA ANNOTATION?

Page 4: Annotation Processing in Android

LET'S START WITH THE OFFICIAL DEFINITION

Annotations, a form of metadata, provide data about a program that is not part of the program itself.

Annotations have no direct effect on the operation of the code they annotate.

— Oracle

Page 5: Annotation Processing in Android

WHAT CAN ANNOTATIONS DO?1. Provide information for the compiler

2. Allow runtime processing3. Allow compile-time processing

Page 6: Annotation Processing in Android

HOW TO DEFINE AN ANNOTATIONThe simplest annotation can be defined as:

public @interface MyAnnotation {}

and it can be used like this:@MyAnnotationpublic class MyClass {}

Page 7: Annotation Processing in Android

ANNOTATIONS CAN ACCEPT ARGUMENTS

public @interface MyAnnotation { String arg1(); int arg2 default 1; String[] arg3;}

Which can be used like this:@MyAnnotation ( arg1 = "value1", // It's a comma, not a semicolon arg3 = { "value2", "value3" } // Arrays use curly brackets)public class MyClass {}

Page 8: Annotation Processing in Android

ANNOTATIONS CAN BE ANNOTATEDThe most important is @Retention which value can

be:

▸ RetentionPolicy.SOURCE

▸ RetentionPolicy.CLASS

▸ RetentionPolicy.RUNTIME

Page 9: Annotation Processing in Android

ANNOTATIONS CAN BE ANNOTATED PART 2

The other important annotation is @Target which value:

ElementType.ANNOTATION_TYPE ElementType.CONSTRUCTOR

ElementType.FIELD ElementType.LOCAL_VARIABLE

ElementType.METHOD

Page 10: Annotation Processing in Android

ANNOTATIONS CAN BE ANNOTATED PART 3

Other useful annotations:

▸ @Documented

▸ @Inherited

▸ @Repeatable

Page 11: Annotation Processing in Android

AN EXAMPLE ANNOTATION@Retention(RetentionPolicy.CLASS) // Available at compile-time@Target(ElementType.TYPE) // Can only be applied to classes@interface MyAnnotation { String arg1(); int arg2 default 1; String[] arg3;}

Page 12: Annotation Processing in Android

WHAT IS AN ANNOTATION PROCESSOR?

Page 13: Annotation Processing in Android

Annotation Processing is a technique that providesa hook into the Java compile process.

It allows to produce compiler errors and warningsand to generate source code and byte code.

Page 14: Annotation Processing in Android

JSR 269

Page 15: Annotation Processing in Android

HOW DOES IT WORK?

Here's a high-level example:

1. Normal compilation2. First round of annotation processing

3. Second round of annotation processing4. ...

Page 16: Annotation Processing in Android

IMPLEMENTING A PROCESSORpublic abstract class AbstractProcessor implements Processor { // more methods here!

void init( ProcessingEnvironment processingEnv );

abstract boolean process( Set<? extends TypeElement> annotations, RoundEnvironment roundEnv );}

Page 17: Annotation Processing in Android

THE PROCESSING ENVIRONMENT

It provides the tools to write new files and access utility classes.

Here are the most useful methods:// Use Filer to write new filesFiler getFiler();

// Use Elements to manage fields, methods and classesElements getElementUtils();

// Use Types to deal with classes, converting Type to Element, ...Types getTypeUtils();

Page 18: Annotation Processing in Android

THE ROUND ENVIRONMENT

It provides tools to deal with the specific round.The most useful methods are:

// Get the elements annotated with a given annotationSet<? extends Element> getElementsAnnotatedWith(Class<? extends Annotation> a);Set<? extends Element> getElementsAnnotatedWith(TypeElement a);

Page 19: Annotation Processing in Android

THE MOST USELESS ANNOTATIONpublic AnnoyingProcessor extends AbstractProcessor { boolean process( Set<> annotations, RoundEnvironment env) { Messager m = processingEnv.getMessager(); for (TypeElement te : annotations) { for (Element e : env.getElementsAnnotatedWith(te)) { m.printMessage(Diagnostic.Kind.NOTE, "Processing " + e.toString()); } } return true; }}

Page 20: Annotation Processing in Android

REGISTERING YOUR PROCESSOR

1. Package your processor in a Jar file2. The Jar file must contain a file called

javax.annotation.processing.Processor

located in META-INF/services3. This file must contain the fully

qualified name of your processor

Page 21: Annotation Processing in Android

GENERATING JAVA CODE IN YOUR AP

Enter JavaPoet

Page 22: Annotation Processing in Android

MethodSpec main = MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .returns(void.class) .addParameter(String[].class, "args") .addStatement("$T.out.println($S)", System.class, "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());

Page 23: Annotation Processing in Android

TESTING

Testing annotations processors is hard because the execution happens at compile time

Page 24: Annotation Processing in Android

SOME MUCH NEEDED HELP!

Google's compile-testing library

Page 25: Annotation Processing in Android

EXAMPLE 1assert_() // it uses the Truth testing library .about(javaSource()) .that( JavaFileObjects.forSourceString( "HelloWorld", "final class HelloWorld {}" ) ).compilesWithoutError();

Page 26: Annotation Processing in Android

EXAMPLE 2assert_().about(javaSource()) .that(JavaFileObjects.forResource("HelloWorld.java")) .processedWith(new MyAnnotationProcessor()) .compilesWithoutError() .and() .generatesSources( JavaFileObjects.forResource("GeneratedHelloWorld.java"));

Page 27: Annotation Processing in Android

HOW ABOUT ANNOTATION

PROCESSING IN ANDROID?

Page 28: Annotation Processing in Android

PROBLEM 1

The Android framework does not includejavax.annotation.processing

Page 29: Annotation Processing in Android

SOLUTION

Setup your AP to be a Java moduleand to inform your users to use

the Gradle android-apt plugin by Hugo Visser

Page 30: Annotation Processing in Android

PROBLEM 2

Both your library and your AP might depend on the annotations

Page 31: Annotation Processing in Android

SOLUTION

Setup your annotations to be another Java moduleon which both the library and the AP depend on

Page 32: Annotation Processing in Android

PROBLEM 3

Now the Javadoc of your library does not include the annotations

Page 33: Annotation Processing in Android

SOLUTIONandroid.libraryVariants.all { variant -> task("javadoc${variant.name.capitalize()}", type: Javadoc) { description "Generates Javadoc for $variant.name." group 'Docs' source = variant.javaCompile.source source "../annotations/src/main/java" // <-- THIS! ext.androidJar = files(project.android.getBootClasspath()) classpath = files(variant.javaCompile.classpath.files) + ext.androidJar exclude '**/BuildConfig.java' exclude '**/R.java' }}

Page 34: Annotation Processing in Android

ANDROID LIBRARIES THAT USE AP

▸ ButterKnife▸ Dagger▸ Parceler▸ Realm

Page 35: Annotation Processing in Android

Thank you!

Page 36: Annotation Processing in Android

Questions?