package com.example; import com.google.auto.service.AutoService; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.FieldSpec; import com.squareup.javapoet.JavaFile; import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeSpec; import java.io.IOException; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.Processor; import javax.annotation.processing.RoundEnvironment; import javax.lang.model.element.Element; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import javax.lang.model.util.Elements; /** * Intro: Use ComponentName replace Class * Author:zhangxutong * E-mail:mcxtzhang@163.com * Home Page:http://blog.csdn.net/zxt0601 * Created: 2017/1/17. * History: * 2017/02/04 add : Auto bind params in bundle for target Activity/Fragment. */ @AutoService(Processor.class) public class ZRouter2Processor extends AbstractProcessor { private Elements mElementUtils; @Override public synchronized void init(ProcessingEnvironment processingEnv) { super.init(processingEnv); mElementUtils = processingEnv.getElementUtils(); } @Override public Set<String> getSupportedAnnotationTypes() { return Collections.singleton(ZRouter.class.getCanonicalName()); } @Override public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) { //field //TAG FieldSpec TAG = FieldSpec.builder(String.class, "TAG") .addModifiers(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL) .initializer("$S", "zxt/ZRouter") .build(); //private Map<String, String> routerMap; TypeName listString = ParameterizedTypeName.get(Map.class, String.class, String.class); FieldSpec routerMap = FieldSpec.builder(listString, "routerMap") .addModifiers(Modifier.PRIVATE) .build(); //Constructor MethodSpec.Builder constructorBuilder = MethodSpec.constructorBuilder() .addModifiers(Modifier.PRIVATE) .addStatement("routerMap = new $T()", HashMap.class); //traverse annotation named ZRtouer Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(ZRouter.class); for (Element element : elements) { TypeElement typeElement; if (element instanceof TypeElement) { typeElement = (TypeElement) element; } else { return false; } ZRouter zRouter = typeElement.getAnnotation(ZRouter.class); String className = typeElement.getQualifiedName().toString(); constructorBuilder.addStatement("routerMap.put($S, $S)", zRouter.path(), className); //2017 02 04 add auto bind params value in bundle for target activity List<? extends Element> members = mElementUtils.getAllMembers(typeElement); MethodSpec.Builder bindViewMethodSpecBuilder = MethodSpec.methodBuilder("bindParams") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .returns(TypeName.VOID) //RxActivity activity .addParameter(ClassName.get(typeElement.asType()), "activity") .addStatement("$T intent = activity.getIntent()", ClassName.get("android.content", "Intent")) .beginControlFlow("if (null != intent)"); for (Element item : members) { ZParams diView = item.getAnnotation(ZParams.class); if (diView == null) { continue; } bindViewMethodSpecBuilder.addStatement(String.format("activity.%s = intent.getStringExtra(\"%s\")", item.getSimpleName(), diView.key())); } bindViewMethodSpecBuilder.endControlFlow(); TypeSpec typeSpec = TypeSpec.classBuilder("ZParams" + element.getSimpleName() + "Binding") //extends xxx /* .superclass(TypeName.get(typeElement.asType()))*/ .addModifiers(Modifier.PUBLIC, Modifier.FINAL) .addMethod(bindViewMethodSpecBuilder.build()) .build(); JavaFile javaFile = JavaFile.builder(AptUtils.getPkgName(mElementUtils, typeElement), typeSpec).build(); try { javaFile.writeTo(processingEnv.getFiler()); } catch (IOException e) { e.printStackTrace(); } } MethodSpec constructor = constructorBuilder .build(); //inner class ClassName className = ClassName.get(AptUtils.PKG_NAME, "ZRouter"); FieldSpec INSTANCE = FieldSpec.builder(className, "INSTANCE") .addModifiers(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL) .initializer("new $T()", className) .build(); TypeSpec innerClass = TypeSpec.classBuilder("InnerClass") .addModifiers(Modifier.PRIVATE, Modifier.STATIC) .addField(INSTANCE) .build(); //getInstance method MethodSpec methodGetInstance = MethodSpec.methodBuilder("getInstance") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .returns(className) .addStatement("return $N.INSTANCE", innerClass) .build(); //jump method: ClassName activityClass = ClassName.get("android.app", "Activity"); ClassName intentClass = ClassName.get("android.content", "Intent"); ClassName componentNameClass = ClassName.get("android.content", "ComponentName"); ClassName bundleClass = ClassName.get("android.os", "Bundle"); ClassName textUtilsClass = ClassName.get("android.text", "TextUtils"); ClassName logClass = ClassName.get("android.util", "Log"); MethodSpec jump = MethodSpec.methodBuilder("jump") .addModifiers(Modifier.PUBLIC) .addParameter(activityClass, "activity") .addParameter(String.class, "where") .addParameter(bundleClass, "bundle") .addStatement("String clsFullName = routerMap.get(where)") .beginControlFlow("if ($T.isEmpty(clsFullName))" , textUtilsClass) .addStatement("$T.e(TAG, \"Error in jump() where = [\" + where + \"] not found in routerMap!\")" , logClass) .endControlFlow() .beginControlFlow("else") .addStatement("$T intent = new $T()" , intentClass, intentClass) .addStatement("intent.setComponent(new $T(activity.getPackageName(), clsFullName))" , componentNameClass) .beginControlFlow("if (null != bundle)") .addStatement("intent.putExtras(bundle)") .endControlFlow() .addStatement("activity.startActivity(intent)") .addStatement("$T.d(TAG, \"Jump success:\" + where)" , logClass) .endControlFlow() .build(); //for result MethodSpec jump2 = MethodSpec.methodBuilder("jump") .addModifiers(Modifier.PUBLIC) .addParameter(activityClass, "activity") .addParameter(String.class, "where") .addParameter(bundleClass, "bundle") .addParameter(int.class, "requestCode") .addStatement("String clsFullName = routerMap.get(where)") .beginControlFlow("if ($T.isEmpty(clsFullName))" , textUtilsClass) .addStatement("$T.e(TAG, \"Error in jump() where = [\" + where + \"] not found in routerMap!\")" , logClass) .endControlFlow() .beginControlFlow("else") .addStatement("$T intent = new $T()" , intentClass, intentClass) .addStatement("intent.setComponent(new $T(activity.getPackageName(), clsFullName))" , componentNameClass) .beginControlFlow("if (null != bundle)") .addStatement("intent.putExtras(bundle)") .endControlFlow() .addStatement("activity.startActivityForResult(intent, requestCode)") .addStatement("$T.d(TAG, \"Jump success:\" + where)" , logClass) .endControlFlow() .build(); //class TypeSpec hello = TypeSpec.classBuilder("ZRouter") .addModifiers(Modifier.PUBLIC) .addField(TAG) .addField(routerMap) .addMethod(constructor) .addType(innerClass) .addMethod(methodGetInstance) .addMethod(jump) .addMethod(jump2) .build(); try { JavaFile.builder(AptUtils.PKG_NAME, hello) .build() .writeTo(processingEnv.getFiler()); } catch (IOException e) { e.printStackTrace(); } return true; } }