編譯時註解(轉)

weixin_33907511發表於2017-09-14

原文http://fucknmb.com/2017/02/07/%E7%BC%96%E8%AF%91%E6%97%B6%E6%B3%A8%E8%A7%A35%E6%AD%A5%E8%B5%B0/

新建Java Module
http://fucknmb.com/2017/02/07/%E7%BC%96%E8%AF%91%E6%97%B6%E6%B3%A8%E8%A7%A35%E6%AD%A5%E8%B5%B0/new-module.png

引入auto-service(自動生成services下檔案)和javapoet(生成java檔案)

compile 'com.google.auto.service:auto-service:1.0-rc2'
compile 'com.squareup:javapoet:1.8.0'

編寫註解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
@Inherited
public @interface Api {
    String scope();
    String name();
    String version();
}

建立AbstractProcessor實現類

重寫getSupportedSourceVersion,getSupportedAnnotationTypes和process方法。注意在類上加入註解AutoService,便會自動生成META-INF下的services檔案

@AutoService(Processor.class)
public class AnnotationProcessor extends AbstractProcessor {
    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> supportedAnnotationTypes = new HashSet<>();
        supportedAnnotationTypes.add(Api.class.getCanonicalName());
        return supportedAnnotationTypes;
    }
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        return false;
    }
}

實現process方法,根據註解生成對應程式碼

public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
    Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(Api.class);
    for (Element e : elements) {
        //獲得對應的註解
        Api api = e.getAnnotation(Api.class);
        System.out.println("*");
        //使用javapoet開始生成程式碼
        TypeSpec clazz = TypeSpec.classBuilder(api.name().toUpperCase() + "Request")
                .addJavadoc("Generated request for network\n")
                .addSuperinterface(Serializable.class)
                .build();
        JavaFile javaFile = JavaFile.builder("com.funcknmb.api", clazz)
                .build();
        //生成的程式碼寫入檔案
        try {
            JavaFileObject fileObject = processingEnv.getFiler().createSourceFile("com.funcknmb.api." + api.name().toUpperCase() + "Request");
            processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Creating " + fileObject.toUri());
            Writer writer = fileObject.openWriter();
            javaFile.writeTo(writer);
            writer.close();
        } catch (IOException x) {
            processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, x.toString());
        }
    }
    return false;
}

總結

編寫的註解以及process的實現只是做個模板,具體情況視情況而定。

相關文章