Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Hello, Annotation Processing!
Search
Tatsuya Maki
December 10, 2016
Technology
320
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Hello, Annotation Processing!
Introduction to Annotation Processing.
Tatsuya Maki
December 10, 2016
Other Decks in Technology
See All in Technology
フルカイテン株式会社 エンジニア向け採用資料
fullkaiten
0
12k
JSONataとAWS Step Functionsで目指すRuntimelessな世界
mu7889yoon
1
500
猫でもわかるKiro Web
kentapapa
1
110
【技術的負債conf】事業成長に伴う技術的負債の説明責任とAIによるモニタリング、認知的負債について
i35_267
4
2.2k
EventBridge に「合流」はない ― サーバーレスのワークフローを育てるということ / No Join in EventBridge
yusukeshimizu
2
550
Goodbye ShellScript, Hello File-based App
shunsock
0
1.1k
GitHub Agentic Workflows を触ってみる
htkym
2
630
アクセスキーこわい やめかたと漏らさない工夫
sassssan68
1
800
認知負荷を吸収し、プロダクトをまたぐPR Preview基盤の設計事例
taiki45
2
320
AI 時代のスタートアップエコシステ厶から考究する技術的負債との向き合い方
m3m0r7
PRO
3
2.7k
C#未経験の僕がAIに読めるコードを書かせるまで
maguroalternative
0
300
Hermes Agentで、AIが調べて記事を書くブログを作った話
blueb
0
110
Featured
See All Featured
Reflections from 52 weeks, 52 projects
jeffersonlam
356
21k
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
830
Rails Girls Zürich Keynote
gr2m
96
14k
How to Think Like a Performance Engineer
csswizardry
28
2.8k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
360
31k
Heart Work Chapter 1 - Part 1
lfama
PRO
10
36k
Neural Spatial Audio Processing for Sound Field Analysis and Control
skoyamalab
0
520
The Organizational Zoo: Understanding Human Behavior Agility Through Metaphoric Constructive Conversations (based on the works of Arthur Shelley, Ph.D)
kimpetersen
PRO
0
470
Collaborative Software Design: How to facilitate domain modelling decisions
baasie
1
330
A Tale of Four Properties
chriscoyier
163
24k
Tips & Tricks on How to Get Your First Job In Tech
honzajavorek
1
770
Stop Working from a Prison Cell
hatefulcrawdad
274
21k
Transcript
@Hello("Annotation Processing!") December 10, 2016 Tatsuya Maki
2. Annotation Processorをつくる 1. Annotation Processingをしる 3. Annotation Processorをつかう
2. Annotation Processorをつくる 1. Annotation Processingをしる 3. Annotation Processorをつかう
AutoValue https://github.com/google/auto
@AutoValue public abstract class User { public abstract String name();
public abstract int age(); }
final class AutoValue_User extends User { private final String name;
private final int age; AutoValue_User(String name, int age) { if (name == null) { throw new NullPointerException("Null name"); } this.name = name; this.age = age; } @Override public String name() { return name; } @Override public int age() { return age; } @Override public String toString() { return "User{" + "name=" + name + ", " + "age=" + age + "}"; } @Override public boolean equals(Object o) { if (o == this) { return true; }
Butter Knife https://github.com/JakeWharton/butterknife/
public class MainActivity extends AppCompatActivity { @BindView(R.id.fab) FloatingActionButton fab;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); } @OnClick(R.id.fab) void showSnackBar(View view) { Snackbar.make(view, "FloatingActionButton is clicked!", Snackbar.LENGTH_LONG) .setAction("Action", null).show(); } }
public class MainActivity_ViewBinding<T extends MainActivity> implements Unbinder { protected T
target; private View view2131492974; @UiThread public MainActivity_ViewBinding(final T target, View source) { this.target = target; View view; view = Utils.findRequiredView(source, R.id.fab, "field 'fab' and method 'showSnackBar'"); target.fab = Utils.castView(view, R.id.fab, "field 'fab'", FloatingActionButton.class); view2131492974 = view; view.setOnClickListener(new DebouncingOnClickListener() { @Override public void doClick(View p0) { target.showSnackBar(p0); } }); } @Override @CallSuper public void unbind() { T target = this.target; if (target == null) throw new IllegalStateException("Bindings already cleared."); target.fab = null; view2131492974.setOnClickListener(null); view2131492974 = null; this.target = null; } }
Dagger 2 https://github.com/google/dagger
@ActivityScope @Component(modules = {ActivityModule.class}) public interface ActivityComponent { void inject(@NonNull
MainActivity activity); }
public final class DaggerActivityComponent implements ActivityComponent { private DaggerActivityComponent(Builder builder)
{ assert builder != null; } public static Builder builder() { return new Builder(); } public static ActivityComponent create() { return builder().build(); } @Override public void inject(MainActivity activity) { MembersInjectors.<MainActivity>noOp().injectMembers(activity); } public static final class Builder { private Builder() { } public ActivityComponent build() { return new DaggerActivityComponent(this); } public Builder activityModule(ActivityModule activityModule) { Preconditions.checkNotNull(activityModule); return this; } } }
Annotation Processingは、 JSR 269で定義されている仕様。 コンパイル時にアノテーションを処理する。 Pluggable Annotation Processor APIのこと。
*.java *.class
*.java Parse & Enter 構文解析し、シンボルテーブルへ入力 *.class
*.java Parse & Enter Annotation Processing アノテーションを処理 *.class
*.java Parse & Enter Annotation Processing 新しいファイルが生成されると再処理 *.class
*.java *.class Parse & Enter Annotation Processing Analyze & Generate
構文木を分析し、classファイルに変換
ソースコードを生成するので安心。 実行時に余計な処理をしないので高速。 コンパイル時に型が検証できるので安全。 Reflectionと比較して、
2. Annotation Processorをつくる 1. Annotation Processingをしる 3. Annotation Processorをつかう
Annotationの実装 2 1 3 AnnotationProcessorの実装 AnnotationProcessorを登録
Annotationの実装 2 1 3 AnnotationProcessorの実装 AnnotationProcessorを登録
@Target(ElementType.TYPE) @Retention(RetentionPolicy.CLASS) public @interface MyAnnotation { String message(); }
@Target(ElementType.TYPE) @Retention(RetentionPolicy.CLASS) public @interface MyAnnotation { String message(); }
@Target(ElementType.TYPE) @Retention(RetentionPolicy.CLASS) public @interface MyAnnotation { String message(); }
@Target(ElementType.TYPE) @Retention(RetentionPolicy.CLASS) public @interface MyAnnotation { String message(); }
@Target(ElementType.TYPE) @Retention(RetentionPolicy.CLASS) public @interface MyAnnotation { String message(); }
Annotationの実装 2 1 3 AnnotationProcessorの実装 AnnotationProcessorを登録
public interface Processor { Set<String> getSupportedOptions(); Set<String> getSupportedAnnotationTypes();
SourceVersion getSupportedSourceVersion(); void init(ProcessingEnvironment processingEnv); boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv); Iterable<? extends Completion> getCompletions(Element element, AnnotationMirror annotation, ExecutableElement member, String userText); }
public class MyAnnotationProcessor extends AbstractProcessor { @Override public Set<String> getSupportedAnnotationTypes()
{ return Collections.singleton(MyAnnotation.class.getCanonicalName()); } @Override public SourceVersion getSupportedSourceVersion() { return SourceVersion.latestSupported(); } @Override public synchronized void init(ProcessingEnvironment environment) { super.init(environment); messager = environment.getMessager(); elements = environment.getElementUtils(); types = environment.getTypeUtils(); filer = environment.getFiler(); } @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment environment) { ... } }
public class MyAnnotationProcessor extends AbstractProcessor { @Override public Set<String> getSupportedAnnotationTypes()
{ return Collections.singleton(MyAnnotation.class.getCanonicalName()); } @Override public SourceVersion getSupportedSourceVersion() { return SourceVersion.latestSupported(); } @Override public synchronized void init(ProcessingEnvironment environment) { super.init(environment); messager = environment.getMessager(); elements = environment.getElementUtils(); types = environment.getTypeUtils(); filer = environment.getFiler(); } @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment environment) { ... } }
public class MyAnnotationProcessor extends AbstractProcessor { @Override public Set<String> getSupportedAnnotationTypes()
{ return Collections.singleton(MyAnnotation.class.getCanonicalName()); } @Override public SourceVersion getSupportedSourceVersion() { return SourceVersion.latestSupported(); } @Override public synchronized void init(ProcessingEnvironment environment) { super.init(environment); messager = environment.getMessager(); elements = environment.getElementUtils(); types = environment.getTypeUtils(); filer = environment.getFiler(); } @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment environment) { ... } }
public class MyAnnotationProcessor extends AbstractProcessor { @Override public Set<String> getSupportedAnnotationTypes()
{ return Collections.singleton(MyAnnotation.class.getCanonicalName()); } @Override public SourceVersion getSupportedSourceVersion() { return SourceVersion.latestSupported(); } @Override public synchronized void init(ProcessingEnvironment environment) { super.init(environment); messager = environment.getMessager(); elements = environment.getElementUtils(); types = environment.getTypeUtils(); filer = environment.getFiler(); } @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment environment) { ... } }
public class MyAnnotationProcessor extends AbstractProcessor { @Override public Set<String> getSupportedAnnotationTypes()
{ return Collections.singleton(MyAnnotation.class.getCanonicalName()); } @Override public SourceVersion getSupportedSourceVersion() { return SourceVersion.latestSupported(); } @Override public synchronized void init(ProcessingEnvironment environment) { super.init(environment); messager = environment.getMessager(); elements = environment.getElementUtils(); types = environment.getTypeUtils(); filer = environment.getFiler(); } @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment environment) { ... } }
public class MyAnnotationProcessor extends AbstractProcessor { @Override public Set<String> getSupportedAnnotationTypes()
{ return Collections.singleton(MyAnnotation.class.getCanonicalName()); } @Override public SourceVersion getSupportedSourceVersion() { return SourceVersion.latestSupported(); } @Override public synchronized void init(ProcessingEnvironment environment) { super.init(environment); messager = environment.getMessager(); elements = environment.getElementUtils(); types = environment.getTypeUtils(); filer = environment.getFiler(); } @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment environment) { ... } }
public class MyAnnotationProcessor extends AbstractProcessor { @Override public boolean process(Set<?
extends TypeElement> annotations, RoundEnvironment environment) { final Set<? extends Element> elements = environment.getElementsAnnotatedWith(MyAnnotation.class); elements.forEach(element -> { final Name className = element.getSimpleName(); final Name packageName = this.elements.getPackageOf(element).getQualifiedName(); try { final JavaFileObject file = filer.createSourceFile(packageName + ".MyAnnotation_" + className); try (final Writer writer = file.openWriter()) { writer.append("package ").append(packageName).append(";\n\n") .append("public class MyAnnotation_").append(className).append(" {\n\n") .append(" @Override\n") .append(" public String toString() {\n"); final MyAnnotation annotation = element.getAnnotation(MyAnnotation.class); final String message = annotation.message(); writer.append(" return \"").append(message).append("\";\n") .append(" }\n") .append("}\n"); writer.flush(); } } catch (IOException e) { messager.printMessage(Diagnostic.Kind.ERROR, "Failed to generate a file:" + packageName); } }); return false; } }
public class MyAnnotationProcessor extends AbstractProcessor { @Override public boolean process(Set<?
extends TypeElement> annotations, RoundEnvironment environment) { final Set<? extends Element> elements = environment.getElementsAnnotatedWith(MyAnnotation.class); elements.forEach(element -> { final Name className = element.getSimpleName(); final Name packageName = this.elements.getPackageOf(element).getQualifiedName(); try { final JavaFileObject file = filer.createSourceFile(packageName + ".MyAnnotation_" + className); try (final Writer writer = file.openWriter()) { writer.append("package ").append(packageName).append(";\n\n") .append("public class MyAnnotation_").append(className).append(" {\n\n") .append(" @Override\n") .append(" public String toString() {\n"); final MyAnnotation annotation = element.getAnnotation(MyAnnotation.class); final String value = annotation.value(); writer.append(" return \"").append(value).append("\";\n") .append(" }\n") .append("}\n"); writer.flush(); } } catch (IOException e) { messager.printMessage(Diagnostic.Kind.ERROR, "Failed to generate a file:" + packageName); } }); return false; } }
public class MyAnnotationProcessor extends AbstractProcessor { @Override public boolean process(Set<?
extends TypeElement> annotations, RoundEnvironment environment) { final Set<? extends Element> elements = environment.getElementsAnnotatedWith(MyAnnotation.class); elements.forEach(element -> { final Name className = element.getSimpleName(); final Name packageName = this.elements.getPackageOf(element).getQualifiedName(); try { final JavaFileObject file = filer.createSourceFile(packageName + ".MyAnnotation_" + className); try (final Writer writer = file.openWriter()) { writer.append("package ").append(packageName).append(";\n\n") .append("public class MyAnnotation_").append(className).append(" {\n\n") .append(" @Override\n") .append(" public String toString() {\n"); final MyAnnotation annotation = element.getAnnotation(MyAnnotation.class); final String value = annotation.value(); writer.append(" return \"").append(value).append("\";\n") .append(" }\n") .append("}\n"); writer.flush(); } } catch (IOException e) { messager.printMessage(Diagnostic.Kind.ERROR, "Failed to generate a file:" + packageName); } }); return false; } }
public class MyAnnotationProcessor extends AbstractProcessor { @Override public boolean process(Set<?
extends TypeElement> annotations, RoundEnvironment environment) { final Set<? extends Element> elements = environment.getElementsAnnotatedWith(MyAnnotation.class); elements.forEach(element -> { final Name className = element.getSimpleName(); final Name packageName = this.elements.getPackageOf(element).getQualifiedName(); try { final JavaFileObject file = filer.createSourceFile(packageName + ".MyAnnotation_" + className); try (final Writer writer = file.openWriter()) { writer.append("package ").append(packageName).append(";\n\n") .append("public class MyAnnotation_").append(className).append(" {\n\n") .append(" @Override\n") .append(" public String toString() {\n"); final MyAnnotation annotation = element.getAnnotation(MyAnnotation.class); final String value = annotation.value(); writer.append(" return \"").append(value).append("\";\n") .append(" }\n") .append("}\n"); writer.flush(); } } catch (IOException e) { messager.printMessage(Diagnostic.Kind.ERROR, "Failed to generate a file:" + packageName); } }); return false; } }
public class MyAnnotationProcessor extends AbstractProcessor { @Override public boolean process(Set<?
extends TypeElement> annotations, RoundEnvironment environment) { final Set<? extends Element> elements = environment.getElementsAnnotatedWith(MyAnnotation.class); elements.forEach(element -> { final Name className = element.getSimpleName(); final Name packageName = this.elements.getPackageOf(element).getQualifiedName(); try { final JavaFileObject file = filer.createSourceFile(packageName + ".MyAnnotation_" + className); try (final Writer writer = file.openWriter()) { writer.append("package ").append(packageName).append(";\n\n") .append("public class MyAnnotation_").append(className).append(" {\n\n") .append(" @Override\n") .append(" public String toString() {\n"); final MyAnnotation annotation = element.getAnnotation(MyAnnotation.class); final String value = annotation.value(); writer.append(" return \"").append(value).append("\";\n") .append(" }\n") .append("}\n"); writer.flush(); } } catch (IOException e) { messager.printMessage(Diagnostic.Kind.ERROR, "Failed to generate a file:" + packageName); } }); return false; } }
public class MyAnnotationProcessor extends AbstractProcessor { @Override public boolean process(Set<?
extends TypeElement> annotations, RoundEnvironment environment) { final Set<? extends Element> elements = environment.getElementsAnnotatedWith(MyAnnotation.class); elements.forEach(element -> { final Name className = element.getSimpleName(); final Name packageName = this.elements.getPackageOf(element).getQualifiedName(); try { final JavaFileObject file = filer.createSourceFile(packageName + ".MyAnnotation_" + className); try (final Writer writer = file.openWriter()) { writer.append("package ").append(packageName).append(";\n\n") .append("public class MyAnnotation_").append(className).append(" {\n\n") .append(" @Override\n") .append(" public String toString() {\n"); final MyAnnotation annotation = element.getAnnotation(MyAnnotation.class); final String value = annotation.value(); writer.append(" return \"").append(value).append("\";\n") .append(" }\n") .append("}\n"); writer.flush(); } } catch (IOException e) { messager.printMessage(Diagnostic.Kind.ERROR, "Failed to generate a file:" + packageName); } }); return false; } }
public class MyAnnotationProcessor extends AbstractProcessor { @Override public boolean process(Set<?
extends TypeElement> annotations, RoundEnvironment environment) { final Set<? extends Element> elements = environment.getElementsAnnotatedWith(MyAnnotation.class); elements.forEach(element -> { final Name className = element.getSimpleName(); final Name packageName = this.elements.getPackageOf(element).getQualifiedName(); try { final JavaFileObject file = filer.createSourceFile(packageName + ".MyAnnotation_" + className); try (final Writer writer = file.openWriter()) { writer.append("package ").append(packageName).append(";\n\n") .append("public class MyAnnotation_").append(className).append(" {\n\n") .append(" @Override\n") .append(" public String toString() {\n"); final MyAnnotation annotation = element.getAnnotation(MyAnnotation.class); final String message = annotation.message(); writer.append(" return \"").append(message).append("\";\n") .append(" }\n") .append("}\n"); writer.flush(); } } catch (IOException e) { messager.printMessage(Diagnostic.Kind.ERROR, "Failed to generate a file:" + packageName); } }); return false; } }
public class MyAnnotationProcessor extends AbstractProcessor { @Override public boolean process(Set<?
extends TypeElement> annotations, RoundEnvironment environment) { final Set<? extends Element> elements = environment.getElementsAnnotatedWith(MyAnnotation.class); elements.forEach(element -> { final Name className = element.getSimpleName(); final Name packageName = this.elements.getPackageOf(element).getQualifiedName(); try { final JavaFileObject file = filer.createSourceFile(packageName + ".MyAnnotation_" + className); try (final Writer writer = file.openWriter()) { writer.append("package ").append(packageName).append(";\n\n") .append("public class MyAnnotation_").append(className).append(" {\n\n") .append(" @Override\n") .append(" public String toString() {\n"); final MyAnnotation annotation = element.getAnnotation(MyAnnotation.class); final String message = annotation.message(); writer.append(" return \"").append(message).append("\";\n") .append(" }\n") .append("}\n"); writer.flush(); } } catch (IOException e) { messager.printMessage(Diagnostic.Kind.ERROR, "Failed to generate a file:" + packageName); } }); return false; } }
public class MyAnnotationProcessor extends AbstractProcessor { @Override public boolean process(Set<?
extends TypeElement> annotations, RoundEnvironment environment) { final Set<? extends Element> elements = environment.getElementsAnnotatedWith(MyAnnotation.class); elements.forEach(element -> { final Name className = element.getSimpleName(); final Name packageName = this.elements.getPackageOf(element).getQualifiedName(); try { final JavaFileObject file = filer.createSourceFile(packageName + ".MyAnnotation_" + className); try (final Writer writer = file.openWriter()) { writer.append("package ").append(packageName).append(";\n\n") .append("public class MyAnnotation_").append(className).append(" {\n\n") .append(" @Override\n") .append(" public String toString() {\n"); final MyAnnotation annotation = element.getAnnotation(MyAnnotation.class); final String message = annotation.message(); writer.append(" return \"").append(message).append("\";\n") .append(" }\n") .append("}\n"); writer.flush(); } } catch (IOException e) { messager.printMessage(Diagnostic.Kind.ERROR, "Failed to generate a file:" + packageName); } }); return false; } }
public class MyAnnotationProcessor extends AbstractProcessor { @Override public boolean process(Set<?
extends TypeElement> annotations, RoundEnvironment environment) { final Set<? extends Element> elements = environment.getElementsAnnotatedWith(MyAnnotation.class); elements.forEach(element -> { final Name className = element.getSimpleName(); final Name packageName = this.elements.getPackageOf(element).getQualifiedName(); try { final JavaFileObject file = filer.createSourceFile(packageName + ".MyAnnotation_" + className); try (final Writer writer = file.openWriter()) { writer.append("package ").append(packageName).append(";\n\n") .append("public class MyAnnotation_").append(className).append(" {\n\n") .append(" @Override\n") .append(" public String toString() {\n"); final MyAnnotation annotation = element.getAnnotation(MyAnnotation.class); final String value = annotation.value(); writer.append(" return \"").append(value).append("\";\n") .append(" }\n") .append("}\n"); writer.flush(); } } catch (IOException e) { messager.printMessage(Diagnostic.Kind.ERROR, "Failed to generate a file:" + packageName); } }); return false; } }
Annotationの実装 2 1 3 AnnotationProcessorの実装 AnnotationProcessorを登録
. |--src | |-- main | | |-- java |
| | `-- io.t28.example.MyAnnotationProcessor.java | | `-- resources | | `-- META-INF.services | | `-- javax.annotation.processing.Processor | `-- test | `-- java | `-- io.t28.example.MyAnnotationProcessorTest.java `-- build.gradle
. |--src | |-- main | | |-- java |
| | `-- io.t28.example.MyAnnotationProcessor.java | | `-- resources | | `-- META-INF.services | | `-- javax.annotation.processing.Processor | `-- test | `-- java | `-- io.t28.example.MyAnnotationProcessorTest.java `-- build.gradle
2. Annotation Processorをつくる 1. Annotation Processingをしる 3. Annotation Processorをつかう
dependencies { compile project(':library') annotationProcessor project(':processor') }
@MyAnnotation(message = "Hello, world.") public class MyClass { }
public class MyAnnotation_MyClass { @Override public String toString() {
return "Hello, world."; } }
まとめ
2. コンパイル時にコードの検証や生成が可能 1. Pluggable Annotation Processing 3. ボイラープレートコードの生成に効果的
おまけ
AutoService https://github.com/google/auto/tree/master/service Compile Testing https://github.com/google/compile-testing JavaPoet https://github.com/square/javapoet
@Thanks