atom
This commit is contained in:
24
arouter_compiler/build.gradle
Normal file
24
arouter_compiler/build.gradle
Normal file
@@ -0,0 +1,24 @@
|
||||
apply plugin: 'java-library'
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
|
||||
// AS 4.3.1 -> 4.0.1 没有问题
|
||||
// As-3.4.1 + gradle-5.1.1-all + auto-service:1.0-rc4
|
||||
compileOnly'com.google.auto.service:auto-service:1.0-rc4'
|
||||
annotationProcessor'com.google.auto.service:auto-service:1.0-rc4'
|
||||
|
||||
// 帮助我们通过类调用的形式来生成Java代码
|
||||
implementation "com.squareup:javapoet:1.9.0"
|
||||
|
||||
// 引入annotation,处理@ARouter注解
|
||||
implementation project(':arouter_annotation')
|
||||
}
|
||||
|
||||
// java控制台输出中文乱码
|
||||
tasks.withType(JavaCompile) {
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
sourceCompatibility = "7"
|
||||
targetCompatibility = "7"
|
||||
@@ -0,0 +1 @@
|
||||
i/
|
||||
@@ -0,0 +1 @@
|
||||
i/
|
||||
@@ -0,0 +1,2 @@
|
||||
com.xiangxue.arouter_compiler.ARouterProcessor
|
||||
com.xiangxue.arouter_compiler.ParameterProcessor
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
arouter_compiler/build/libs/arouter_compiler.jar
Normal file
BIN
arouter_compiler/build/libs/arouter_compiler.jar
Normal file
Binary file not shown.
2
arouter_compiler/build/tmp/jar/MANIFEST.MF
Normal file
2
arouter_compiler/build/tmp/jar/MANIFEST.MF
Normal file
@@ -0,0 +1,2 @@
|
||||
Manifest-Version: 1.0
|
||||
|
||||
@@ -0,0 +1,470 @@
|
||||
package com.xiangxue.arouter_compiler;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.squareup.javapoet.ClassName;
|
||||
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 com.squareup.javapoet.WildcardTypeName;
|
||||
import com.xiangxue.arouter_annotation.ARouter;
|
||||
import com.xiangxue.arouter_annotation.bean.RouterBean;
|
||||
import com.xiangxue.arouter_compiler.utils.ProcessorConfig;
|
||||
import com.xiangxue.arouter_compiler.utils.ProcessorUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
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.Filer;
|
||||
import javax.annotation.processing.Messager;
|
||||
import javax.annotation.processing.ProcessingEnvironment;
|
||||
import javax.annotation.processing.Processor;
|
||||
import javax.annotation.processing.RoundEnvironment;
|
||||
import javax.annotation.processing.SupportedAnnotationTypes;
|
||||
import javax.annotation.processing.SupportedOptions;
|
||||
import javax.annotation.processing.SupportedSourceVersion;
|
||||
import javax.lang.model.SourceVersion;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
import javax.lang.model.util.Elements;
|
||||
import javax.lang.model.util.Types;
|
||||
import javax.tools.Diagnostic;
|
||||
|
||||
/**
|
||||
* 同学们注意:编码此类,记住就是一个字(细心,细心,细心),出了问题debug真的不好调试
|
||||
*/
|
||||
|
||||
// AutoService则是固定的写法,加个注解即可
|
||||
// 通过auto-service中的@AutoService可以自动生成AutoService注解处理器,用来注册
|
||||
// 用来生成 META-INF/services/javax.annotation.processing.Processor 文件
|
||||
@AutoService(Processor.class)
|
||||
|
||||
// 允许/支持的注解类型,让注解处理器处理
|
||||
@SupportedAnnotationTypes({ProcessorConfig.AROUTER_PACKAGE})
|
||||
|
||||
// 指定JDK编译版本
|
||||
@SupportedSourceVersion(SourceVersion.RELEASE_7)
|
||||
|
||||
// 注解处理器接收的参数
|
||||
@SupportedOptions({ProcessorConfig.OPTIONS, ProcessorConfig.APT_PACKAGE})
|
||||
|
||||
public class ARouterProcessor extends AbstractProcessor {
|
||||
|
||||
// 操作Element的工具类(类,函数,属性,其实都是Element)
|
||||
private Elements elementTool;
|
||||
|
||||
// type(类信息)的工具类,包含用于操作TypeMirror的工具方法
|
||||
private Types typeTool;
|
||||
|
||||
// Message用来打印 日志相关信息
|
||||
private Messager messager;
|
||||
|
||||
// 文件生成器, 类 资源 等,就是最终要生成的文件 是需要Filer来完成的
|
||||
private Filer filer;
|
||||
|
||||
private String options; // 各个模块传递过来的模块名 例如:app order personal
|
||||
private String aptPackage; // 各个模块传递过来的目录 用于统一存放 apt生成的文件
|
||||
|
||||
// 仓库一 Path 缓存一
|
||||
// Map<"personal", List<RouterBean>>
|
||||
private Map<String, List<RouterBean>> mAllPathMap = new HashMap<>(); // 目前是一个
|
||||
|
||||
// 仓库二 Group 缓存二
|
||||
// Map<"personal", "ARouter$$Path$$personal.class">
|
||||
private Map<String, String> mAllGroupMap = new HashMap<>();
|
||||
|
||||
// 做初始化工作,就相当于 Activity中的 onCreate函数一样的作用
|
||||
@Override
|
||||
public synchronized void init(ProcessingEnvironment processingEnvironment) {
|
||||
super.init(processingEnvironment);
|
||||
|
||||
elementTool = processingEnvironment.getElementUtils();
|
||||
messager = processingEnvironment.getMessager();
|
||||
filer = processingEnvironment.getFiler();
|
||||
typeTool = processingEnvironment.getTypeUtils();
|
||||
|
||||
// 只有接受到 App壳 传递过来的书籍,才能证明我们的 APT环境搭建完成
|
||||
options = processingEnvironment.getOptions().get(ProcessorConfig.OPTIONS);
|
||||
aptPackage = processingEnvironment.getOptions().get(ProcessorConfig.APT_PACKAGE);
|
||||
messager.printMessage(Diagnostic.Kind.NOTE, ">>>>>>>>>>>>>>>>>>>>>> options:" + options);
|
||||
messager.printMessage(Diagnostic.Kind.NOTE, ">>>>>>>>>>>>>>>>>>>>>> aptPackage:" + aptPackage);
|
||||
if (options != null && aptPackage != null) {
|
||||
messager.printMessage(Diagnostic.Kind.NOTE, "APT 环境搭建完成....");
|
||||
} else {
|
||||
messager.printMessage(Diagnostic.Kind.NOTE, "APT 环境有问题,请检查 options 与 aptPackage 为null...");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 相当于main函数,开始处理注解
|
||||
* 注解处理器的核心方法,处理具体的注解,生成Java文件
|
||||
*
|
||||
* @param set 使用了支持处理注解的节点集合
|
||||
* @param roundEnvironment 当前或是之前的运行环境,可以通过该对象查找的注解。
|
||||
* @return true 表示后续处理器不会再处理(已经处理完成)
|
||||
*/
|
||||
@Override
|
||||
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
|
||||
if (set.isEmpty()) {
|
||||
messager.printMessage(Diagnostic.Kind.NOTE, "并没有发现 被@ARouter注解的地方呀");
|
||||
return false; // 没有机会处理
|
||||
}
|
||||
|
||||
// TODO 新增点1
|
||||
TypeElement callType = elementTool.getTypeElement(ProcessorConfig.CALL);
|
||||
TypeMirror callMirror = callType.asType(); // 自描述 callMirror
|
||||
|
||||
// 获取所有被 @ARouter 注解的 元素集合
|
||||
Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(ARouter.class);
|
||||
|
||||
// 通过Element工具类,获取Activity,Callback类型
|
||||
TypeElement activityType = elementTool.getTypeElement(ProcessorConfig.ACTIVITY_PACKAGE);
|
||||
// 显示类信息(获取被注解的节点,类节点)这也叫自描述 Mirror
|
||||
TypeMirror activityMirror = activityType.asType();
|
||||
|
||||
// 遍历所有的类节点
|
||||
for (Element element : elements) {
|
||||
// 获取类节点,获取包节点 (com.xiangxue.xxxxxx)
|
||||
// String packageName = elementTool.getPackageOf(element).getQualifiedName().toString();
|
||||
|
||||
// 获取简单类名,例如:MainActivity
|
||||
String className = element.getSimpleName().toString();
|
||||
messager.printMessage(Diagnostic.Kind.NOTE, "被@ARetuer注解的类有:" + className); // 打印出 就证明APT没有问题
|
||||
|
||||
// 拿到注解
|
||||
ARouter aRouter = element.getAnnotation(ARouter.class);
|
||||
|
||||
// 下面是练习 JavaPoet
|
||||
/**
|
||||
* package com.example.helloworld;
|
||||
*
|
||||
* public final class HelloWorld {
|
||||
* public static void main(String[] args) {
|
||||
* System.out.println("Hello, JavaPoet!");
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
// 1.方法
|
||||
/*MethodSpec mainMethod = 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();
|
||||
// 2.类
|
||||
TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
|
||||
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
|
||||
.addMethod(mainMethod)
|
||||
.build();
|
||||
// 3.包
|
||||
JavaFile packagef = JavaFile.builder("com.derry.study", helloWorld).build();
|
||||
// 去生成
|
||||
try {
|
||||
packagef.writeTo(filer);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
messager.printMessage(Diagnostic.Kind.NOTE, "生成失败,请检查代码...");
|
||||
}*/
|
||||
|
||||
// 先JavaPoet 写一个简单示例,方法--->类--> 包,是倒序写的思路哦
|
||||
/*
|
||||
package com.example.helloworld;
|
||||
|
||||
public final class HelloWorld {
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("Hello, JavaPoet!");
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
// 方法
|
||||
/*MethodSpec mainMethod = MethodSpec.methodBuilder("main")
|
||||
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
|
||||
.returns(void.class)
|
||||
.addParameter(System[].class, "args")
|
||||
// 增加main方法里面的内容
|
||||
.addStatement("$T.out.println($S)", System.class, "AAAAAAAAAAA!")
|
||||
.build();
|
||||
// 类 Testapp Testorder
|
||||
TypeSpec testClass = TypeSpec.classBuilder("Test" + options)
|
||||
.addMethod(mainMethod)
|
||||
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
|
||||
.build();
|
||||
// 包
|
||||
JavaFile packagef = JavaFile.builder("com.xiangxue.test22", testClass).build();
|
||||
try {
|
||||
packagef.writeTo(filer);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
messager.printMessage(Diagnostic.Kind.NOTE, "生成Test文件时失败,异常:" + e.getMessage());
|
||||
}*/
|
||||
|
||||
// TODO 一系列的检查工作
|
||||
// 在循环里面,对 “路由对象” 进行封装
|
||||
RouterBean routerBean = new RouterBean.Builder()
|
||||
.addGroup(aRouter.group())
|
||||
.addPath(aRouter.path())
|
||||
.addElement(element)
|
||||
.build();
|
||||
|
||||
// ARouter注解的类 必须继承 Activity
|
||||
TypeMirror elementMirror = element.asType(); // Main2Activity的具体详情 例如:继承了 Activity
|
||||
if (typeTool.isSubtype(elementMirror, activityMirror)) { // activityMirror android.app.Activity描述信息
|
||||
routerBean.setTypeEnum(RouterBean.TypeEnum.ACTIVITY); // 最终证明是 Activity
|
||||
} else if (typeTool.isSubtype(elementMirror, callMirror)) { // TODO 新增点2
|
||||
routerBean.setTypeEnum(RouterBean.TypeEnum.CALL);
|
||||
}
|
||||
|
||||
else { // Derry.java 的干法 就会抛出异常
|
||||
// 不匹配抛出异常,这里谨慎使用!考虑维护问题
|
||||
throw new RuntimeException("@ARouter注解目前仅限用于Activity类之上");
|
||||
}
|
||||
|
||||
if (checkRouterPath(routerBean)) {
|
||||
messager.printMessage(Diagnostic.Kind.NOTE, "RouterBean Check Success:" + routerBean.toString());
|
||||
|
||||
// 赋值 mAllPathMap 集合里面去
|
||||
List<RouterBean> routerBeans = mAllPathMap.get(routerBean.getGroup());
|
||||
|
||||
// 如果从Map中找不到key为:bean.getGroup()的数据,就新建List集合再添加进Map
|
||||
if (ProcessorUtils.isEmpty(routerBeans)) { // 仓库一 没有东西
|
||||
routerBeans = new ArrayList<>();
|
||||
routerBeans.add(routerBean);
|
||||
mAllPathMap.put(routerBean.getGroup(), routerBeans);// 加入仓库一
|
||||
} else {
|
||||
routerBeans.add(routerBean);
|
||||
}
|
||||
} else { // ERROR 编译期发生异常
|
||||
messager.printMessage(Diagnostic.Kind.ERROR, "@ARouter注解未按规范配置,如:/app/MainActivity");
|
||||
}
|
||||
} // TODO end for 同学们注意:在循环外面了 (此循环结束后,仓库一 缓存一 就存好所有 Path值了)
|
||||
|
||||
// mAllPathMap 里面有值了
|
||||
// 定义(生成类文件实现的接口) 有 Path Group
|
||||
TypeElement pathType = elementTool.getTypeElement(ProcessorConfig.AROUTER_API_PATH); // ARouterPath描述
|
||||
TypeElement groupType = elementTool.getTypeElement(ProcessorConfig.AROUTER_API_GROUP); // ARouterGroup描述
|
||||
|
||||
// TODO 第一大步:系列PATH
|
||||
try {
|
||||
createPathFile(pathType); // 生成 Path类
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
messager.printMessage(Diagnostic.Kind.NOTE, "在生成PATH模板时,异常了 e:" + e.getMessage());
|
||||
}
|
||||
|
||||
// TODO 第二大步:组头(带头大哥)
|
||||
try {
|
||||
createGroupFile(groupType, pathType);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
messager.printMessage(Diagnostic.Kind.NOTE, "在生成GROUP模板时,异常了 e:" + e.getMessage());
|
||||
}
|
||||
|
||||
return true; // 坑:必须写返回值,表示处理@ARouter注解完成
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成路由组Group文件,如:ARouter$$Group$$app
|
||||
* @param groupType ARouterLoadGroup接口信息
|
||||
* @param pathType ARouterLoadPath接口信息
|
||||
*/
|
||||
private void createGroupFile(TypeElement groupType, TypeElement pathType) throws IOException {
|
||||
// 仓库二 缓存二 判断是否有需要生成的类文件
|
||||
if (ProcessorUtils.isEmpty(mAllGroupMap) || ProcessorUtils.isEmpty(mAllPathMap)) return;
|
||||
|
||||
// 返回值 这一段 Map<String, Class<? extends ARouterPath>>
|
||||
TypeName methodReturns = ParameterizedTypeName.get(
|
||||
ClassName.get(Map.class), // Map
|
||||
ClassName.get(String.class), // Map<String,
|
||||
|
||||
// Class<? extends ARouterPath>> 难度
|
||||
ParameterizedTypeName.get(ClassName.get(Class.class),
|
||||
// ? extends ARouterPath
|
||||
WildcardTypeName.subtypeOf(ClassName.get(pathType))) // ? extends ARouterLoadPath
|
||||
// WildcardTypeName.supertypeOf() 做实验 ? super
|
||||
|
||||
// 最终的:Map<String, Class<? extends ARouterPath>>
|
||||
);
|
||||
|
||||
// 1.方法 public Map<String, Class<? extends ARouterPath>> getGroupMap() {
|
||||
MethodSpec.Builder methodBuidler = MethodSpec.methodBuilder(ProcessorConfig.GROUP_METHOD_NAME) // 方法名
|
||||
.addAnnotation(Override.class) // 重写注解 @Override
|
||||
.addModifiers(Modifier.PUBLIC) // public修饰符
|
||||
.returns(methodReturns); // 方法返回值
|
||||
|
||||
// Map<String, Class<? extends ARouterPath>> groupMap = new HashMap<>();
|
||||
methodBuidler.addStatement("$T<$T, $T> $N = new $T<>()",
|
||||
ClassName.get(Map.class),
|
||||
ClassName.get(String.class),
|
||||
|
||||
// Class<? extends ARouterPath> 难度
|
||||
ParameterizedTypeName.get(ClassName.get(Class.class),
|
||||
WildcardTypeName.subtypeOf(ClassName.get(pathType))), // ? extends ARouterPath
|
||||
ProcessorConfig.GROUP_VAR1,
|
||||
ClassName.get(HashMap.class));
|
||||
|
||||
// groupMap.put("personal", ARouter$$Path$$personal.class);
|
||||
// groupMap.put("order", ARouter$$Path$$order.class);
|
||||
for (Map.Entry<String, String> entry : mAllGroupMap.entrySet()) {
|
||||
methodBuidler.addStatement("$N.put($S, $T.class)",
|
||||
ProcessorConfig.GROUP_VAR1, // groupMap.put
|
||||
entry.getKey(), // order, personal ,app
|
||||
ClassName.get(aptPackage, entry.getValue()));
|
||||
}
|
||||
|
||||
// return groupMap;
|
||||
methodBuidler.addStatement("return $N", ProcessorConfig.GROUP_VAR1);
|
||||
|
||||
// 最终生成的类文件名 ARouter$$Group$$ + personal
|
||||
String finalClassName = ProcessorConfig.GROUP_FILE_NAME + options;
|
||||
|
||||
messager.printMessage(Diagnostic.Kind.NOTE, "APT生成路由组Group类文件:" +
|
||||
aptPackage + "." + finalClassName);
|
||||
|
||||
// 生成类文件:ARouter$$Group$$app
|
||||
JavaFile.builder(aptPackage, // 包名
|
||||
TypeSpec.classBuilder(finalClassName) // 类名
|
||||
.addSuperinterface(ClassName.get(groupType)) // 实现ARouterLoadGroup接口 implements ARouterGroup
|
||||
.addModifiers(Modifier.PUBLIC) // public修饰符
|
||||
.addMethod(methodBuidler.build()) // 方法的构建(方法参数 + 方法体)
|
||||
.build()) // 类构建完成
|
||||
.build() // JavaFile构建完成
|
||||
.writeTo(filer); // 文件生成器开始生成类文件
|
||||
}
|
||||
|
||||
/**
|
||||
* 系列Path的类 生成工作
|
||||
* @param pathType ARouterPath 高层的标准
|
||||
* @throws IOException
|
||||
*/
|
||||
private void createPathFile(TypeElement pathType) throws IOException {
|
||||
// 判断 map仓库中,是否有需要生成的文件
|
||||
if (ProcessorUtils.isEmpty(mAllPathMap)) {
|
||||
return; // 连缓存一 仓库一 里面 值都没有 不用干活了
|
||||
}
|
||||
|
||||
// 倒序生成代码
|
||||
|
||||
// 任何的class类型,必须包装
|
||||
// Map<String, RouterBean>
|
||||
TypeName methodReturn = ParameterizedTypeName.get(
|
||||
ClassName.get(Map.class), // Map
|
||||
ClassName.get(String.class), // Map<String,
|
||||
ClassName.get(RouterBean.class) // Map<String, RouterBean>
|
||||
);
|
||||
|
||||
// 遍历仓库 app,order,personal
|
||||
for (Map.Entry<String, List<RouterBean>> entry : mAllPathMap.entrySet()) { // personal
|
||||
// 1.方法
|
||||
MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder(ProcessorConfig.PATH_METHOD_NAME)
|
||||
.addAnnotation(Override.class) // 给方法上添加注解 @Override
|
||||
.addModifiers(Modifier.PUBLIC) // public修饰符
|
||||
.returns(methodReturn) // 把Map<String, RouterBean> 加入方法返回
|
||||
;
|
||||
|
||||
// Map<String, RouterBean> pathMap = new HashMap<>(); // $N == 变量 为什么是这个,因为变量有引用 所以是$N
|
||||
methodBuilder.addStatement("$T<$T, $T> $N = new $T<>()",
|
||||
ClassName.get(Map.class), // Map
|
||||
ClassName.get(String.class), // Map<String,
|
||||
ClassName.get(RouterBean.class), // Map<String, RouterBean>
|
||||
ProcessorConfig.PATH_VAR1, // Map<String, RouterBean> pathMap
|
||||
ClassName.get(HashMap.class) // Map<String, RouterBean> pathMap = new HashMap<>();
|
||||
);
|
||||
|
||||
// 必须要循环,因为有多个
|
||||
// pathMap.put("/personal/Personal_Main2Activity", RouterBean.create(RouterBean.TypeEnum.ACTIVITY,
|
||||
// Personal_Main2Activity.class);
|
||||
// pathMap.put("/personal/Personal_MainActivity", RouterBean.create(RouterBean.TypeEnum.ACTIVITY));
|
||||
List<RouterBean> pathList = entry.getValue();
|
||||
/**
|
||||
$N == 变量 变量有引用 所以 N
|
||||
$L == TypeEnum.ACTIVITY
|
||||
*/
|
||||
// personal 的细节
|
||||
for (RouterBean bean : pathList) {
|
||||
methodBuilder.addStatement("$N.put($S, $T.create($T.$L, $T.class, $S, $S))",
|
||||
ProcessorConfig.PATH_VAR1, // pathMap.put
|
||||
bean.getPath(), // "/personal/Personal_Main2Activity"
|
||||
ClassName.get(RouterBean.class), // RouterBean
|
||||
ClassName.get(RouterBean.TypeEnum.class), // RouterBean.Type
|
||||
bean.getTypeEnum(), // 枚举类型:ACTIVITY
|
||||
ClassName.get((TypeElement) bean.getElement()), // MainActivity.class Main2Activity.class
|
||||
bean.getPath(), // 路径名
|
||||
bean.getGroup() // 组名
|
||||
);
|
||||
} // TODO end for
|
||||
|
||||
// return pathMap;
|
||||
methodBuilder.addStatement("return $N", ProcessorConfig.PATH_VAR1);
|
||||
|
||||
// TODO 注意:不能像以前一样,1.方法,2.类 3.包, 因为这里面有implements ,所以 方法和类要合为一体生成才行,这是特殊情况
|
||||
|
||||
// 最终生成的类文件名 ARouter$$Path$$personal
|
||||
String finalClassName = ProcessorConfig.PATH_FILE_NAME + entry.getKey();
|
||||
|
||||
messager.printMessage(Diagnostic.Kind.NOTE, "APT生成路由Path类文件:" +
|
||||
aptPackage + "." + finalClassName);
|
||||
|
||||
// 生成类文件:ARouter$$Path$$personal
|
||||
JavaFile.builder(aptPackage, // 包名 APT 存放的路径
|
||||
TypeSpec.classBuilder(finalClassName) // 类名
|
||||
.addSuperinterface(ClassName.get(pathType)) // 实现ARouterLoadPath接口 implements ARouterPath==pathType
|
||||
.addModifiers(Modifier.PUBLIC) // public修饰符
|
||||
.addMethod(methodBuilder.build()) // 方法的构建(方法参数 + 方法体)
|
||||
.build()) // 类构建完成
|
||||
.build() // JavaFile构建完成
|
||||
.writeTo(filer); // 文件生成器开始生成类文件
|
||||
|
||||
// 仓库二 缓存二 非常重要一步,注意:PATH 路径文件生成出来了,才能赋值路由组mAllGroupMap
|
||||
mAllGroupMap.put(entry.getKey(), finalClassName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验@ARouter注解的值,如果group未填写就从必填项path中截取数据
|
||||
* @param bean 路由详细信息,最终实体封装类
|
||||
*/
|
||||
private final boolean checkRouterPath(RouterBean bean) {
|
||||
String group = bean.getGroup(); // 同学们,一定要记住: "app" "order" "personal"
|
||||
String path = bean.getPath(); // 同学们,一定要记住: "/app/MainActivity" "/order/Order_MainActivity" "/personal/Personal_MainActivity"
|
||||
|
||||
// 校验
|
||||
// @ARouter注解中的path值,必须要以 / 开头(模仿阿里Arouter规范)
|
||||
if (ProcessorUtils.isEmpty(path) || !path.startsWith("/")) {
|
||||
messager.printMessage(Diagnostic.Kind.ERROR, "@ARouter注解中的path值,必须要以 / 开头");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 比如开发者代码为:path = "/MainActivity",最后一个 / 符号必然在字符串第1位
|
||||
if (path.lastIndexOf("/") == 0) {
|
||||
// 架构师定义规范,让开发者遵循
|
||||
messager.printMessage(Diagnostic.Kind.ERROR, "@ARouter注解未按规范配置,如:/app/MainActivity");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 从第一个 / 到第二个 / 中间截取,如:/app/MainActivity 截取出 app,order,personal 作为group
|
||||
String finalGroup = path.substring(1, path.indexOf("/", 1));
|
||||
|
||||
// app,order,personal == options
|
||||
|
||||
// @ARouter注解中的group有赋值情况
|
||||
if (!ProcessorUtils.isEmpty(group) && !group.equals(options)) {
|
||||
// 架构师定义规范,让开发者遵循
|
||||
messager.printMessage(Diagnostic.Kind.ERROR, "@ARouter注解中的group值必须和子模块名一致!");
|
||||
return false;
|
||||
} else {
|
||||
bean.setGroup(finalGroup);
|
||||
}
|
||||
|
||||
// 如果真的返回ture RouterBean.group xxxxx 赋值成功 没有问题
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
package com.xiangxue.arouter_compiler;
|
||||
|
||||
import com.squareup.javapoet.ClassName;
|
||||
import com.squareup.javapoet.MethodSpec;
|
||||
import com.squareup.javapoet.ParameterSpec;
|
||||
import com.squareup.javapoet.TypeName;
|
||||
import com.xiangxue.arouter_annotation.Parameter;
|
||||
import com.xiangxue.arouter_compiler.utils.ProcessorConfig;
|
||||
import com.xiangxue.arouter_compiler.utils.ProcessorUtils;
|
||||
|
||||
import javax.annotation.processing.Messager;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.type.TypeKind;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
import javax.lang.model.util.Elements;
|
||||
import javax.lang.model.util.Types;
|
||||
import javax.tools.Diagnostic;
|
||||
|
||||
/*
|
||||
目的 生成以下代码:
|
||||
@Override
|
||||
public void getParameter(Object targetParameter) {
|
||||
Personal_MainActivity t = (Personal_MainActivity) targetParameter;
|
||||
t.name = t.getIntent().getStringExtra("name");
|
||||
t.sex = t.getIntent().getStringExtra("sex");
|
||||
}
|
||||
*/
|
||||
public class ParameterFactory {
|
||||
|
||||
// 方法的构建
|
||||
private MethodSpec.Builder method;
|
||||
|
||||
// 类名,如:MainActivity / Personal_MainActivity
|
||||
private ClassName className;
|
||||
|
||||
// Messager用来报告错误,警告和其他提示信息
|
||||
private Messager messager;
|
||||
|
||||
// type(类信息)工具类,包含用于操作TypeMirror的工具方法
|
||||
private Types typeUtils;
|
||||
|
||||
// 获取元素接口信息(生成类文件需要的接口实现类)
|
||||
private TypeMirror callMirror;
|
||||
|
||||
// 不想用户使用此构造函数,必须使用Builder设计模式
|
||||
private ParameterFactory(Builder builder) {
|
||||
this.messager = builder.messager;
|
||||
this.className = builder.className;
|
||||
this.typeUtils = builder.typeUtils;
|
||||
|
||||
// 生成此方法
|
||||
// 通过方法参数体构建方法体:public void getParameter(Object target) {
|
||||
method = MethodSpec.methodBuilder(ProcessorConfig.PARAMETER_METHOD_NAME)
|
||||
.addAnnotation(Override.class)
|
||||
.addModifiers(Modifier.PUBLIC)
|
||||
.addParameter(builder.parameterSpec);
|
||||
|
||||
// call自描述 Call接口的
|
||||
this.callMirror = builder.elementUtils
|
||||
.getTypeElement(ProcessorConfig.CALL)
|
||||
.asType();
|
||||
}
|
||||
|
||||
/** 只有一行
|
||||
* Personal_MainActivity t = (Personal_MainActivity) targetParameter;
|
||||
*/
|
||||
public void addFirstStatement() {
|
||||
method.addStatement("$T t = ($T) " + ProcessorConfig.PARAMETER_NAME, className, className);
|
||||
}
|
||||
|
||||
public MethodSpec build() {
|
||||
return method.build();
|
||||
}
|
||||
|
||||
/** 多行 循环 复杂
|
||||
* 构建方体内容,如:t.s = t.getIntent.getStringExtra("s");
|
||||
* @param element 被注解的属性元素
|
||||
*/
|
||||
public void buildStatement(Element element) {
|
||||
// 遍历注解的属性节点 生成函数体
|
||||
TypeMirror typeMirror = element.asType();
|
||||
|
||||
// 获取 TypeKind 枚举类型的序列号
|
||||
int type = typeMirror.getKind().ordinal();
|
||||
|
||||
// 获取属性名 name age sex
|
||||
String fieldName = element.getSimpleName().toString();
|
||||
|
||||
// 获取注解的值
|
||||
String annotationValue = element.getAnnotation(Parameter.class).name();
|
||||
|
||||
// 配合: t.age = t.getIntent().getBooleanExtra("age", t.age == 9);
|
||||
// 判断注解的值为空的情况下的处理(注解中有name值就用注解值)
|
||||
annotationValue = ProcessorUtils.isEmpty(annotationValue) ? fieldName : annotationValue;
|
||||
|
||||
// TODO 最终拼接的前缀:
|
||||
String finalValue = "t." + fieldName;
|
||||
|
||||
// t.s = t.getIntent().
|
||||
// TODO t.name = t.getIntent().getStringExtra("name");
|
||||
String methodContent = finalValue + " = t.getIntent().";
|
||||
|
||||
// TypeKind 枚举类型不包含String
|
||||
if (type == TypeKind.INT.ordinal()) {
|
||||
// t.s = t.getIntent().getIntExtra("age", t.age);
|
||||
methodContent += "getIntExtra($S, " + finalValue + ")"; // 有默认值
|
||||
} else if (type == TypeKind.BOOLEAN.ordinal()) {
|
||||
// t.s = t.getIntent().getBooleanExtra("isSuccess", t.age);
|
||||
methodContent += "getBooleanExtra($S, " + finalValue + ")"; // 有默认值
|
||||
} else { // String 类型,没有序列号的提供 需要我们自己完成
|
||||
// t.s = t.getIntent.getStringExtra("s");
|
||||
// typeMirror.toString() java.lang.String
|
||||
if (typeMirror.toString().equalsIgnoreCase(ProcessorConfig.STRING)) {
|
||||
// String类型
|
||||
methodContent += "getStringExtra($S)"; // 没有默认值
|
||||
} else if (typeUtils.isSubtype(typeMirror, callMirror)) { // 你居然实现了Call接口
|
||||
// t.orderDrawable = (OrderDrawable) RouterManager.getInstance().build("/order/getDrawable").navigation(t);
|
||||
methodContent = "t." + fieldName + " = ($T) $T.getInstance().build($S).navigation(t)";
|
||||
method.addStatement(methodContent,
|
||||
TypeName.get(typeMirror),
|
||||
ClassName.get(ProcessorConfig.AROUTER_API_PACKAGE, ProcessorConfig.ROUTER_MANAGER),
|
||||
annotationValue);
|
||||
return;
|
||||
} else { // 对象的传输
|
||||
methodContent = "t.getIntent().getSerializableExtra($S)";
|
||||
}
|
||||
}
|
||||
|
||||
// 健壮代码
|
||||
if (methodContent.contains("Serializable")) {
|
||||
// t.student=(Student) t.getIntent().getSerializableExtra("student"); 同学们注意:为了强转
|
||||
method.addStatement(finalValue + "=($T)" + methodContent, ClassName.get(element.asType()) ,annotationValue);
|
||||
}
|
||||
else if (methodContent.endsWith(")")) { // 抱歉 全部的 getBooleanExtra getIntExtra getStringExtra
|
||||
// 参数二 9 赋值进去了
|
||||
// t.age = t.getIntent().getBooleanExtra("age", t.age == 9);
|
||||
method.addStatement(methodContent, annotationValue);
|
||||
} else {
|
||||
messager.printMessage(Diagnostic.Kind.ERROR, "目前暂支持String、int、boolean传参");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 为了完成Builder构建者设计模式
|
||||
*/
|
||||
public static class Builder {
|
||||
|
||||
// Messager用来报告错误,警告和其他提示信息
|
||||
private Messager messager;
|
||||
|
||||
// 操作Element工具类 (类、函数、属性都是Element)
|
||||
private Elements elementUtils;
|
||||
|
||||
// type(类信息)工具类,包含用于操作TypeMirror的工具方法
|
||||
private Types typeUtils;
|
||||
|
||||
// 类名,如:MainActivity
|
||||
private ClassName className;
|
||||
|
||||
// 方法参数体
|
||||
private ParameterSpec parameterSpec;
|
||||
|
||||
public Builder(ParameterSpec parameterSpec) {
|
||||
this.parameterSpec = parameterSpec;
|
||||
}
|
||||
|
||||
public Builder setMessager(Messager messager) {
|
||||
this.messager = messager;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setElementUtils(Elements elementUtils) {
|
||||
this.elementUtils = elementUtils;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setTypeUtils(Types typeUtils) {
|
||||
this.typeUtils = typeUtils;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setClassName(ClassName className) {
|
||||
this.className = className;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ParameterFactory build() {
|
||||
if (parameterSpec == null) {
|
||||
throw new IllegalArgumentException("parameterSpec方法参数体为空");
|
||||
}
|
||||
|
||||
if (className == null) {
|
||||
throw new IllegalArgumentException("方法内容中的className为空");
|
||||
}
|
||||
|
||||
if (messager == null) {
|
||||
throw new IllegalArgumentException("messager为空,Messager用来报告错误、警告和其他提示信息");
|
||||
}
|
||||
|
||||
return new ParameterFactory(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
package com.xiangxue.arouter_compiler;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.squareup.javapoet.ClassName;
|
||||
import com.squareup.javapoet.JavaFile;
|
||||
import com.squareup.javapoet.ParameterSpec;
|
||||
import com.squareup.javapoet.TypeName;
|
||||
import com.squareup.javapoet.TypeSpec;
|
||||
import com.xiangxue.arouter_annotation.Parameter;
|
||||
import com.xiangxue.arouter_compiler.utils.ProcessorConfig;
|
||||
import com.xiangxue.arouter_compiler.utils.ProcessorUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
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.Filer;
|
||||
import javax.annotation.processing.Messager;
|
||||
import javax.annotation.processing.ProcessingEnvironment;
|
||||
import javax.annotation.processing.Processor;
|
||||
import javax.annotation.processing.RoundEnvironment;
|
||||
import javax.annotation.processing.SupportedAnnotationTypes;
|
||||
import javax.annotation.processing.SupportedSourceVersion;
|
||||
import javax.lang.model.SourceVersion;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.util.Elements;
|
||||
import javax.lang.model.util.Types;
|
||||
import javax.tools.Diagnostic;
|
||||
|
||||
@AutoService(Processor.class) // 开启
|
||||
@SupportedAnnotationTypes({ProcessorConfig.PARAMETER_PACKAGE}) // 我们服务的注解
|
||||
@SupportedSourceVersion(SourceVersion.RELEASE_7) // 同学们:这个是必填的哦
|
||||
public class ParameterProcessor extends AbstractProcessor {
|
||||
|
||||
private Elements elementUtils; // 类信息
|
||||
private Types typeUtils; // 具体类型
|
||||
private Messager messager; // 日志
|
||||
private Filer filer; // 生成器
|
||||
|
||||
// 临时map存储,用来存放被@Parameter注解的属性集合,生成类文件时遍历
|
||||
// key:类节点, value:被@Parameter注解的属性集合
|
||||
private Map<TypeElement, List<Element>> tempParameterMap = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public synchronized void init(ProcessingEnvironment processingEnvironment) {
|
||||
super.init(processingEnvironment);
|
||||
elementUtils = processingEnvironment.getElementUtils();
|
||||
typeUtils = processingEnvironment.getTypeUtils();
|
||||
messager = processingEnvironment.getMessager();
|
||||
filer = processingEnvironment.getFiler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
|
||||
// 由于返回了 false 就不需要一下代码了
|
||||
/*if (set.isEmpty()) {
|
||||
messager.printMessage(Diagnostic.Kind.NOTE, "并没有发现 被@ARouter注解的地方呀");
|
||||
return false; // 没有机会处理
|
||||
}*/
|
||||
|
||||
// 扫描的时候,看那些地方使用到了@Parameter注解
|
||||
if (!ProcessorUtils.isEmpty(set)) {
|
||||
// 获取所有被 @Parameter 注解的 元素(属性)集合
|
||||
Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(Parameter.class);
|
||||
|
||||
if (!ProcessorUtils.isEmpty(elements)) {
|
||||
// TODO 给仓库 存储相关信息
|
||||
for (Element element : elements) { // element == name, sex, age
|
||||
|
||||
// 字段节点的上一个节点 类节点==Key
|
||||
// 注解在属性的上面,属性节点父节点 是 类节点
|
||||
TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();
|
||||
|
||||
// enclosingElement == Personal_MainActivity == key
|
||||
|
||||
if (tempParameterMap.containsKey(enclosingElement)) {
|
||||
tempParameterMap.get(enclosingElement).add(element);
|
||||
} else { // 没有key Personal_MainActivity
|
||||
List<Element> fields = new ArrayList<>();
|
||||
fields.add(element);
|
||||
tempParameterMap.put(enclosingElement, fields); // 加入缓存
|
||||
}
|
||||
} // for end 缓存 tempParameterMap有值了
|
||||
|
||||
// TODO 生成类文件
|
||||
// 判断是否有需要生成的类文件
|
||||
if (ProcessorUtils.isEmpty(tempParameterMap)) return true;
|
||||
|
||||
TypeElement activityType = elementUtils.getTypeElement(ProcessorConfig.ACTIVITY_PACKAGE);
|
||||
TypeElement parameterType = elementUtils.getTypeElement(ProcessorConfig.AROUTER_AIP_PARAMETER_GET);
|
||||
|
||||
// 生成方法
|
||||
// Object targetParameter
|
||||
ParameterSpec parameterSpec = ParameterSpec.builder(TypeName.OBJECT, ProcessorConfig.PARAMETER_NAME).build();
|
||||
|
||||
// 循环遍历 缓存tempParameterMap
|
||||
// 可能很多地方都使用了 @Parameter注解,那么就需要去遍历 仓库
|
||||
for (Map.Entry<TypeElement, List<Element>> entry : tempParameterMap.entrySet()) {
|
||||
// key: Personal_MainActivity
|
||||
// value: [name,sex,age]
|
||||
TypeElement typeElement = entry.getKey();
|
||||
|
||||
// 非Activity直接报错
|
||||
// 如果类名的类型和Activity类型不匹配
|
||||
if (!typeUtils.isSubtype(typeElement.asType(), activityType.asType())) {
|
||||
throw new RuntimeException("@Parameter注解目前仅限用于Activity类之上");
|
||||
}
|
||||
|
||||
// 是Activity
|
||||
// 获取类名 == Personal_MainActivity
|
||||
ClassName className = ClassName.get(typeElement);
|
||||
|
||||
// 方法生成成功
|
||||
ParameterFactory factory = new ParameterFactory.Builder(parameterSpec)
|
||||
.setMessager(messager)
|
||||
.setElementUtils(elementUtils) // TODO 新增点
|
||||
.setTypeUtils(typeUtils)
|
||||
.setClassName(className)
|
||||
.build();
|
||||
|
||||
// Personal_MainActivity t = (Personal_MainActivity) targetParameter;
|
||||
factory.addFirstStatement();
|
||||
|
||||
// 难点 多行
|
||||
for (Element element : entry.getValue()) {
|
||||
factory.buildStatement(element);
|
||||
}
|
||||
|
||||
// 最终生成的类文件名(类名$$Parameter) 例如:Personal_MainActivity$$Parameter
|
||||
String finalClassName = typeElement.getSimpleName() + ProcessorConfig.PARAMETER_FILE_NAME;
|
||||
messager.printMessage(Diagnostic.Kind.NOTE, "APT生成获取参数类文件:" +
|
||||
className.packageName() + "." + finalClassName);
|
||||
|
||||
// 开始生成文件,例如:PersonalMainActivity$$Parameter
|
||||
try {
|
||||
JavaFile.builder(className.packageName(), // 包名
|
||||
TypeSpec.classBuilder(finalClassName) // 类名
|
||||
.addSuperinterface(ClassName.get(parameterType)) // implements ParameterGet 实现ParameterLoad接口
|
||||
.addModifiers(Modifier.PUBLIC) // public修饰符
|
||||
.addMethod(factory.build()) // 方法的构建(方法参数 + 方法体)
|
||||
.build()) // 类构建完成
|
||||
.build() // JavaFile构建完成
|
||||
.writeTo(filer); // 文件生成器开始生成类文件
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 1 2 3节课 true 执行两次 为了防止第二有问题 加了if (set.isEmpty()) { 内部机制回来检测一遍 所以有了第二次
|
||||
// 4节课 false 执行一次
|
||||
return false; // 前几年研究 好像记得 执行一次
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package com.xiangxue.arouter_compiler.utils;
|
||||
|
||||
public interface ProcessorConfig {
|
||||
|
||||
// @ARouter注解 的 包名 + 类名
|
||||
String AROUTER_PACKAGE = "com.xiangxue.arouter_annotation.ARouter";
|
||||
|
||||
// 接收参数的TAG标记
|
||||
String OPTIONS = "moduleName"; // 同学们:目的是接收 每个module名称
|
||||
String APT_PACKAGE = "packageNameForAPT"; // 同学们:目的是接收 包名(APT 存放的包名)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// String全类名
|
||||
public static final String STRING_PACKAGE = "java.lang.String";
|
||||
|
||||
// Activity全类名
|
||||
public static final String ACTIVITY_PACKAGE = "android.app.Activity";
|
||||
|
||||
// ARouter api 包名
|
||||
String AROUTER_API_PACKAGE = "com.xiangxue.arouter_api";
|
||||
|
||||
// ARouter api 的 ARouterGroup 高层标准
|
||||
String AROUTER_API_GROUP = AROUTER_API_PACKAGE + ".ARouterGroup";
|
||||
|
||||
// ARouter api 的 ARouterPath 高层标准
|
||||
String AROUTER_API_PATH = AROUTER_API_PACKAGE + ".ARouterPath";
|
||||
|
||||
// 路由组,中的 Path 里面的 方法名
|
||||
String PATH_METHOD_NAME = "getPathMap";
|
||||
|
||||
// 路由组,中的 Group 里面的 方法名
|
||||
String GROUP_METHOD_NAME = "getGroupMap";
|
||||
|
||||
// 路由组,中的 Path 里面 的 变量名 1
|
||||
String PATH_VAR1 = "pathMap";
|
||||
|
||||
// 路由组,中的 Group 里面 的 变量名 1
|
||||
String GROUP_VAR1 = "groupMap";
|
||||
|
||||
// 路由组,PATH 最终要生成的 文件名
|
||||
String PATH_FILE_NAME = "ARouter$$Path$$";
|
||||
|
||||
// 路由组,GROUP 最终要生成的 文件名
|
||||
String GROUP_FILE_NAME = "ARouter$$Group$$";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// @Parameter注解 的 包名 + 类名
|
||||
String PARAMETER_PACKAGE = "com.xiangxue.arouter_annotation.Parameter";
|
||||
|
||||
// ARouter api 的 ParameterGet 高层标准
|
||||
String AROUTER_AIP_PARAMETER_GET = AROUTER_API_PACKAGE + ".ParameterGet";
|
||||
|
||||
// ARouter api 的 ParameterGet 方法参数的名字
|
||||
String PARAMETER_NAME = "targetParameter";
|
||||
|
||||
// ARouter api 的 ParmeterGet 方法的名字
|
||||
String PARAMETER_METHOD_NAME = "getParameter";
|
||||
|
||||
// ARouter aip 的 ParmeterGet 的 生成文件名称 $$Parameter
|
||||
String PARAMETER_FILE_NAME = "$$Parameter";
|
||||
|
||||
// String全类名
|
||||
public static final String STRING = "java.lang.String";
|
||||
|
||||
// ARouter api 的 Call 高层标准
|
||||
String CALL = AROUTER_API_PACKAGE + ".Call";
|
||||
|
||||
// RouterManager类名
|
||||
String ROUTER_MANAGER = "RouterManager";
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.xiangxue.arouter_compiler.utils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 字符串、集合判空工具
|
||||
*/
|
||||
public final class ProcessorUtils {
|
||||
|
||||
// 如果是空 true
|
||||
public static boolean isEmpty(CharSequence cs) {
|
||||
return cs == null || cs.length() == 0;
|
||||
}
|
||||
|
||||
public static boolean isEmpty(Collection<?> coll) {
|
||||
return coll == null || coll.isEmpty();
|
||||
}
|
||||
|
||||
public static boolean isEmpty(final Map<?, ?> map) {
|
||||
return map == null || map.isEmpty();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user