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

ぼくにもできた Annotation Processing

ぼくにもできた Annotation Processing

ぼくにもできた
Annotation Processing

3cca191bf3064fd059ea2c3d6022afbd?s=128

Fumihiko Shiroyama

January 20, 2017
Tweet

More Decks by Fumihiko Shiroyama

Other Decks in Technology

Transcript

  1. ΅͘ʹ΋Ͱ͖ͨ "OOPUBUJPO1SPDFTTJOH !GVTIJSPZBNB

  2. ͳʹ͕Ͱ͖Δ͔ w ΞϊςʔγϣϯΛݩʹίϯύΠϧ࣌ʹίʔυੜ੒Ͱ ͖Δ w ͦΕ͚ͩʜ

  3. ͳʹ͕Ͱ͖Δ͔ w ΞϊςʔγϣϯΛݩʹίϯύΠϧ࣌ʹίʔυੜ੒Ͱ ͖Δ w ͦΕ͚ͩʜ ܕ҆શ ଎౓ͷ٘ਜ਼͕ͳ͍ ੜ੒͞Εͨίʔυ͕ ಡΊΔͷͰ҆৺

  4. ͳʹ͕Ͱ͖ͳ͍͔ w طଘͷίʔυ͕มߋͰ͖ΔΘ͚Ͱ͸ͳ͍ w ੜ੒͞ΕͨίʔυΛͦͷ··࢖͏ w ੜ੒͞ΕͨίʔυʹॲཧΛҕৡ͢Δ

  5. ༻్ w ϘΠϥʔϓϨʔτͷ࡟ݮ w ܕม׵ɺϚοϐϯά

  6. ར༻ྫ " ੜ੒͞ΕͨίʔυΛͦͷ··ར༻͢ΔλΠϓ w "OESPJE"OOPUBUJPOT FUDʜ # ॲཧΛҕৡ͢ΔλΠϓ w #VUUFS,OJGF

    1FSNJTTJPOT%JTQBUDIFS FUDʜ
  7. ར༻ྫ " ੜ੒͞ΕͨίʔυΛͦͷ··ར༻͢ΔλΠϓ w "OESPJE"OOPUBUJPOT FUDʜ # ॲཧΛҕৡ͢ΔλΠϓ w #VUUFS,OJGF

    1FSNJTTJPOT%JTQBUDIFS FUDʜ Ҡৡͷίʔυ͕ෆཁ͕ͩ ར༻ଆͰੜ੒͞ΕͨίʔυΛҙࣝ͢Δඞཁ͕͋Δ .BOJGFTUʹొ࿥͕ඞཁ౳ Ҡৡͷίʔυ͕ඞཁ͕ͩ ݩΫϥε͸ͦͷ··ͰΑ͍
  8. )PXUP.BLF

  9. None
  10. None
  11. MJCSBSZNPEVMF w +BWB-JCSBSZ"OESPJE-JCSBSZ w "OOPUBUJPOΫϥε΍ϥΠϒϥϦͱͯ͠ఏڙ͢Δ࣮ॲཧΛ ॻ͍ͨΫϥε͕ॴଐ w +BWB POMZ+BDL 

    w ίϯύΠϧ࣌ͷΈඞཁͳ৔߹͸QSPWJEFE w BQQϞδϡʔϧ͔ΒϥΠϒϥϦͷίʔυΛࢀর͢Δ৔߹ ͸DPNQJMF
  12. None
  13. QSPDFTTPSNPEVMF w +BWB-JCSBSZ w "OOPUBUJPO1SPDFTTPSͱͦΕʹ෇ਵ͢ΔΫϥε܈ w +BWB,PUMJO XIBUFWFS w MJCSBSZϞδϡʔϧΛDPNQJMFࢦఆͰࢀর

    w BQQϞδϡʔϧ͔Β͸BOOPUBUJPO1SPDFTTPSࢦఆ
  14. None
  15. TBNQMFNPEVMF w "OESPJE"QQ.PEVMF w ඞਢͰ͸ͳ͍͕ಈ࡞֬ೝ΍αϯϓϧͱͯ͠ศར annotationProcessor project(':processor')
 compile project(':library')
 //

    or
 provided project(':library')
  16. @Target({ElementType.TYPE, ElementType.FIELD})
 @Retention(RetentionPolicy.CLASS)
 public @interface MyCoolAnnotation {
 } MJCSBSZNPEVMF

  17. @Target({ElementType.TYPE, ElementType.FIELD})
 @Retention(RetentionPolicy.CLASS)
 public @interface MyCoolAnnotation {
 } MJCSBSZNPEVMF ΞϊςʔγϣϯΛ͚ͭΒΕΔՕॴ

    Ξϊςʔγϣϯ͕࢒Δظؒ
  18. @MyCoolAnnotation
 public class SampleClass {
 @MyCoolAnnotation
 final String text;
 


    public SampleClass(String text) {
 this.text = text;
 }
 } TBNQMFNPEVMF
  19. QSPDFTTPSNPEVMF dependencies {
 compile project(":library")
 compile 'com.squareup:javapoet:1.8.0'
 compile 'com.google.auto.service:auto-service:1.0-rc2'
 }

  20. QSPDFTTPSNPEVMF dependencies {
 compile project(":library")
 compile 'com.squareup:javapoet:1.8.0'
 compile 'com.google.auto.service:auto-service:1.0-rc2'
 }

    ίʔυੜ੒ϥΠϒϥϦ ίϯύΠϧ࣌ʹࣗಈతʹ1SPDFTTPSΛ࣮ߦ
  21. QSPDFTTPSNPEVMF dependencies {
 compile project(":library")
 compile 'com.squareup:javapoet:1.8.0'
 compile 'com.google.auto.service:auto-service:1.0-rc2'
 compile

    'com.google.android:android:4.1.1.4'
 }
 sourceSets {
 main {
 java {
 srcDirs = [‘src/main/java', '../library/src/main/java']
 }
 }
 }
  22. QSPDFTTPSNPEVMF dependencies {
 compile project(":library")
 compile 'com.squareup:javapoet:1.8.0'
 compile 'com.google.auto.service:auto-service:1.0-rc2'
 compile

    'com.google.android:android:4.1.1.4'
 }
 sourceSets {
 main {
 java {
 srcDirs = [‘src/main/java', '../library/src/main/java']
 }
 }
 } BOESPJEMJCSBSZΛࢀর͢Δ৔߹ BOESPJEMJCSBSZΛࢀর͢Δ৔߹
  23. @AutoService(Processor.class)
 public class MyProcessor extends AbstractProcessor {
 @Override
 public Set<String>

    getSupportedAnnotationTypes() {
 return ImmutableSet.of(MyCoolAnnotation.class.getName());
 }
 
 @Override
 public SourceVersion getSupportedSourceVersion() {
 return SourceVersion.latest();
 }
 
 @Override
 public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
 return false;
 }
 } QSPDFTTPSNPEVMF
  24. @AutoService(Processor.class)
 public class MyProcessor extends AbstractProcessor {
 @Override
 public Set<String>

    getSupportedAnnotationTypes() {
 return ImmutableSet.of(MyCoolAnnotation.class.getName());
 }
 
 @Override
 public SourceVersion getSupportedSourceVersion() {
 return SourceVersion.latest();
 }
 
 @Override
 public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
 return false;
 }
 } QSPDFTTPSNPEVMF 1SPDFTTPS͸͜ͷந৅ΫϥεΛܧঝͯ͠ ࡞Δͷ͕ศར
  25. @AutoService(Processor.class)
 public class MyProcessor extends AbstractProcessor {
 @Override
 public Set<String>

    getSupportedAnnotationTypes() {
 return ImmutableSet.of(MyCoolAnnotation.class.getName());
 }
 
 @Override
 public SourceVersion getSupportedSourceVersion() {
 return SourceVersion.latest();
 }
 
 @Override
 public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
 return false;
 }
 } QSPDFTTPSNPEVMF ίϯύΠϧ࣌ʹ͜ͷ1SPDFTTPS͕࣮ߦ͞ΕΔ
  26. @AutoService(Processor.class)
 public class MyProcessor extends AbstractProcessor {
 @Override
 public Set<String>

    getSupportedAnnotationTypes() {
 return ImmutableSet.of(MyCoolAnnotation.class.getName());
 }
 
 @Override
 public SourceVersion getSupportedSourceVersion() {
 return SourceVersion.latest();
 }
 
 @Override
 public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
 return false;
 }
 } QSPDFTTPSNPEVMF ॲཧର৅ͷΞϊςʔγϣϯΛ4FUͰࢦఆ
  27. @AutoService(Processor.class)
 public class MyProcessor extends AbstractProcessor {
 @Override
 public Set<String>

    getSupportedAnnotationTypes() {
 return ImmutableSet.of(MyCoolAnnotation.class.getName());
 }
 
 @Override
 public SourceVersion getSupportedSourceVersion() {
 return SourceVersion.latest();
 }
 
 @Override
 public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
 return false;
 }
 } QSPDFTTPSNPEVMF αϙʔτ্ݶͷ+BWBόʔδϣϯ
  28. @AutoService(Processor.class)
 public class MyProcessor extends AbstractProcessor {
 @Override
 public Set<String>

    getSupportedAnnotationTypes() {
 return ImmutableSet.of(MyCoolAnnotation.class.getName());
 }
 
 @Override
 public SourceVersion getSupportedSourceVersion() {
 return SourceVersion.latest();
 }
 
 @Override
 public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
 return false;
 }
 } QSPDFTTPSNPEVMF ϓϩηοαʔʹΑΔॲཧຊମ
  29. QSPDFTT w QSPDFTT ϝιου͸ॲཧ͢ΔΞϊςʔγϣϯʹԠ ͯ͡ෳ਺ճݺ͹ΕΔɻ͜ΕΛϥ΢ϯυͱ͍͏ɻ w ֤ϥ΢ϯυͰੜ੒͞ΕͨιʔεΛݩʹ͞Βʹ࣍ͷϥ ΢ϯυ͕࣮ߦ͞ΕΔʢ࠷௿ϥ΢ϯυʣ w ͜͜ͰΞϊςʔγϣϯʹԠͯ͡೚ҙͷॲཧΛ΄Ͳ͜

    ͠ɺϑΝΠϧʹग़ྗ͢Δɻ
  30. QSPDFTTPSNPEVMF private Elements elementUtils;
 private Types typeUtils;
 private Messager messager;


    private Filer filer;
 
 @Override
 public synchronized void init(ProcessingEnvironment processingEnvironment) {
 super.init(processingEnvironment);
 
 elementUtils = processingEnvironment.getElementUtils();
 typeUtils = processingEnvironment.getTypeUtils();
 messager = processingEnvironment.getMessager();
 filer = processingEnvironment.getFiler();
 } ศརͳϢʔςΟϦςΟ܈
  31. QSPDFTTPSNPEVMF TypeElement classElement = roundEnvironment.getElementsAnnotatedWith(MyCoolAnnotation.class)
 .stream()
 .filter(element -> element.getKind() ==

    ElementKind.CLASS)
 .map(element -> (TypeElement) element)
 .findFirst()
 .get();
 
 String className = classElement.getSimpleName().toString();
 
 TypeSpec typeSpec = TypeSpec.classBuilder("Sub" + className).build();
 JavaFile javaFile = JavaFile.builder("com.example", typeSpec).build();
 try {
 javaFile.writeTo(filer);
 } catch (IOException e) {
 messager.printMessage(Diagnostic.Kind.ERROR, e.getMessage());
 } ΞϊςʔγϣϯʹରԠ͢Δཁૉ
  32. QSPDFTTPSNPEVMF TypeElement classElement = roundEnvironment.getElementsAnnotatedWith(MyCoolAnnotation.class)
 .stream()
 .filter(element -> element.getKind() ==

    ElementKind.CLASS)
 .map(element -> (TypeElement) element)
 .findFirst()
 .get();
 
 String className = classElement.getSimpleName().toString();
 
 TypeSpec typeSpec = TypeSpec.classBuilder("Sub" + className).build();
 JavaFile javaFile = JavaFile.builder("com.example", typeSpec).build();
 try {
 javaFile.writeTo(filer);
 } catch (IOException e) {
 messager.printMessage(Diagnostic.Kind.ERROR, e.getMessage());
 } ΫϥεΛऔಘ
  33. QSPDFTTPSNPEVMF TypeElement classElement = roundEnvironment.getElementsAnnotatedWith(MyCoolAnnotation.class)
 .stream()
 .filter(element -> element.getKind() ==

    ElementKind.CLASS)
 .map(element -> (TypeElement) element)
 .findFirst()
 .get();
 
 String className = classElement.getSimpleName().toString();
 
 TypeSpec typeSpec = TypeSpec.classBuilder("Sub" + className).build();
 JavaFile javaFile = JavaFile.builder("com.example", typeSpec).build();
 try {
 javaFile.writeTo(filer);
 } catch (IOException e) {
 messager.printMessage(Diagnostic.Kind.ERROR, e.getMessage());
 } +BWBΫϥεΛੜ੒
  34. QSPDFTTPSNPEVMF ੜ੒͞Εͨʂ package com.example;
 
 class SubSampleClass {
 }

  35. &MFNFOU w ΫϥεɺϝιουɺϑΟʔϧυͳͲͷཁૉΛදݱ͢ ΔΫϥε w 5ZQF&MFNFOUʜΫϥε౳ w &YFDVUBCMF&MFNFOUʜϝιου w 7BSJBCMF&MFNFOUʜ౳ʑ

  36. 5ZQF.JSSPS w ܕ৘ใ w ྫ͑͹ΞϊςʔγϣϯʹରԠ͢ΔϑΟʔϧυΛऔಘ ͨ͠ͱͯ͠ɺͦͷܕΛऔಘ͍ͨ࣌͠ͳͲʹ࢖͏ w &MFNFOUBT5ZQF

  37. KBWBQPFU w TRVBSF੡ͷίʔυੜ੒ΞγετϥΠϒϥϦ w "OOPUBUJPO1SPDFTTJOHͰίʔυੜ੒͢Δ্Ͱ ೥ݱࡏσϑΝΫτͰ͋Γඞਢͱߟ͑Δ w ͱͯ΋ॻ͖͖Εͳ͍ͷͰৄ͘͠͸IUUQT HJUIVCDPNTRVBSFKBWBQPFU

  38. KBWBQPFU w 5ZQF4QFDʜܕΛੜ੒ w .FUIPE4QFDʜϝιουΛੜ੒ w 1BSBNFUFS4QFDʜύϥϝʔλΛੜ੒ w 'JFME4QFDʜϑΟʔϧυΛੜ੒

  39. ΅͘ʹ΋Ͱ͖ͨ w $VDLPP w IUUQTHJUIVCDPNTSZNDVDLPP w 7VMUVSF w IUUQTHJUIVCDPNTSZNWVMUVSF

  40. $VDLPP w %FMFHBUJPO1BUUFSOΛ؆୯ʹ࣮૷͢ΔϥΠϒϥϦ w ,PUMJOͷ$MBTT%FMFHBUJPOʹண૝Λಘͨ

  41. public interface Greeter { String sayHello(); String sayHello(String toWhom); }

    public class EnglishGreeter implements Greeter { @Override public String sayHello() { return sayHello("ANONYMOUS"); } @Override public String sayHello(String toWhom) { return String.format("Hello %s !", toWhom); } } $VDLPP ΠϯλϑΣʔε
  42. public interface Greeter { String sayHello(); String sayHello(String toWhom); }

    public class EnglishGreeter implements Greeter { @Override public String sayHello() { return sayHello("ANONYMOUS"); } @Override public String sayHello(String toWhom) { return String.format("Hello %s !", toWhom); } } $VDLPP ࣮૷
  43. @Delegate public abstract class EnglishGreeterWithRecording implements Greeter { @By final

    EnglishGreeter englishGreeter = new EnglishGreeter(); @Override public String sayHello(String toWhom) { // do anything you like here return englishGreeter.sayHello(toWhom); } } $VDLPP
  44. @Delegate public abstract class EnglishGreeterWithRecording implements Greeter { @By final

    EnglishGreeter englishGreeter = new EnglishGreeter(); @Override public String sayHello(String toWhom) { // do anything you like here return englishGreeter.sayHello(toWhom); } } $VDLPP !"CTUSBDU !%FMFHBUF
  45. @Delegate public abstract class EnglishGreeterWithRecording implements Greeter { @By final

    EnglishGreeter englishGreeter = new EnglishGreeter(); @Override public String sayHello(String toWhom) { // do anything you like here return englishGreeter.sayHello(toWhom); } } $VDLPP JNQMFNFOUT
  46. @Delegate public abstract class EnglishGreeterWithRecording implements Greeter { @By final

    EnglishGreeter englishGreeter = new EnglishGreeter(); @Override public String sayHello(String toWhom) { // do anything you like here return englishGreeter.sayHello(toWhom); } } $VDLPP ੜ੒͞ΕͨΫϥε͸ ະ࣮૷ͷϝιου͸ !#Zम০ͨ͠Πϯελϯεʹ ͢΂ҕৡ͞ΕΔ
  47. $VDLPP OFX*OTUBODF Ͱऔಘ // in your code EnglishGreeterWithRecording greeter =

    EnglishGreeterWithRecordingImpl.newInstance(new EnglishGreeter());
  48. annotationProcessor ‘us.shiroyama.android:cuckoo-processor:0.1.0' provided 'us.shiroyama.android:cuckoo:0.1.0' $VDLPP

  49. 7VMUVSF w ίʔϧόοΫΛϥΠϑαΠΫϧ಺Ͱ҆શʹѻ͏ͨΊ ͷϥΠϒϥϦ w 'SBHNFOU5SBOTBDUJPODPNNJUͷ *MMFHBM4UBUF&YDFQUJPOΛى͖ͳ͘͢Δ

  50. void fetchAsynchronously() { /* do heavy asynchronous task here */

    doCallback("finished!"); } void doCallback(@NonNull String message) { FinishDialog.newInstance().show(getSupportFragmentManager(), "TAG"); } 7VMUVSF
  51. void fetchAsynchronously() { /* do heavy asynchronous task here */

    doCallback("finished!"); } void doCallback(@NonNull String message) { FinishDialog.newInstance().show(getSupportFragmentManager(), "TAG"); } 7VMUVSF ඇಉظॲཧ
  52. void fetchAsynchronously() { /* do heavy asynchronous task here */

    doCallback("finished!"); } void doCallback(@NonNull String message) { FinishDialog.newInstance().show(getSupportFragmentManager(), "TAG"); } 7VMUVSF ίʔϧόοΫ PO1BVTFҎ߱͸Ϋϥογϡ
  53. 7VMUVSF @ObserveLifecycle public class YourActivity extends AppCompatActivity { void fetchAsynchronously()

    { SafeMainActivity.doCallbackSafely("finished!"); } @SafeCallback void doCallback(@NonNull String message) { FinishDialog.newInstance().show(getSupportFragmentManager(), "TAG"); } }
  54. 7VMUVSF @ObserveLifecycle public class YourActivity extends AppCompatActivity { void fetchAsynchronously()

    { SafeMainActivity.doCallbackSafely("finished!"); } @SafeCallback void doCallback(@NonNull String message) { FinishDialog.newInstance().show(getSupportFragmentManager(), "TAG"); } } !4BGF$BMMCBDL ͔ΘΓʹͪ͜ΒΛݺͼग़͢
  55. 7VMUVSF @Override protected void onResume() { super.onResume(); SafeMainActivity.register(this); } @Override

    protected void onPause() { SafeMainActivity.unregister(); super.onPause(); }
  56. 7VMUVSF @Override protected void onResume() { super.onResume(); SafeMainActivity.register(this); } @Override

    protected void onPause() { SafeMainActivity.unregister(); super.onPause(); } ҕৡ
  57. 7VMUVSF annotationProcessor 'us.shiroyama.android:vulture-processor:0.1.0' compile 'us.shiroyama.android:vulture:0.1.0'

  58. 5IBOLZPV