自定义注解自动代码构建
新建javaLib-annotation(自定义注解)
build.gradle
apply plugin: 'java-library'
...
//中文乱码问题(错误:编码GBK不可映射字符)
tasks.withType(JavaCompile) {
options.encoding = "UTF-8"
}
sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7
自定义注解
@Target:注解的作用目标
@Target(ElementType.TYPE)——接口、类、枚举、注解
@Target(ElementType.FIELD)——字段、枚举的常量
@Target(ElementType.METHOD)——方法
@Target(ElementType.PARAMETER)——方法参数
@Target(ElementType.CONSTRUCTOR) ——构造函数
@Target(ElementType.LOCAL_VARIABLE)——局部变量
@Target(ElementType.ANNOTATION_TYPE)——注解
@Target(ElementType.PACKAGE)——包
@Retention:注解的保留位置
RetentionPolicy.SOURCE:这种类型的Annotations只在源代码级别保留,编译时就会被忽略,在class字节码文件中不包含。
RetentionPolicy.CLASS:这种类型的Annotations编译时被保留,默认的保留策略,在class文件中存在,但JVM将会忽略,运行时无法获得。
RetentionPolicy.RUNTIME:这种类型的Annotations将被JVM保留,所以他们能在运行时被JVM或其他使用反射机制的代码所读取和使用。
@Document:说明该注解将被包含在javadoc中
@Inherited:说明子类可以继承父类中的该注解
BindViewClass
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface BindViewClass {
String groupName() default "Widget";//默认值="Widget"
String value();//无默认值
}
BindFragmentClass
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface BindFragmentClass {
String value();
}
新建javaLib-processor
build.gradle
apply plugin: 'java-library'
...
dependencies {
implementation 'com.google.auto.service:auto-service:1.0-rc6'
annotationProcessor 'com.google.auto.service:auto-service:1.0-rc6'
implementation 'com.google.auto:auto-common:0.10'
implementation 'com.squareup:javapoet:1.11.1'
implementation project(path: ':annotation')
}
//中文乱码问题(错误:编码GBK不可映射字符)
tasks.withType(JavaCompile) {
options.encoding = "UTF-8"
}
sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7
MyProcessor 自定义AbstractProcessor
@SupportedAnnotationTypes({"BindViewClass全路径","BindFragmentClass全路径"})
@AutoService(Processor.class)
public class MyProcessor extends AbstractProcessor {
private HashMap<String, HashMap<String,Element>> widgets;
private HashMap<String, Element> fragments;
private AnnotatedHelper annotatedHelper;
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
fragments = new HashMap<>();
widgets = new HashMap<>();
annotatedHelper = new AnnotatedHelper();
}
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
fragments.clear();
widgets.clear();
//遍历所有@BindFragmentClass注解
for (Element element : roundEnvironment.getElementsAnnotatedWith(BindFragmentClass.class)) {
BindFragmentClass annotation = element.getAnnotation(BindFragmentClass.class);
fragments.put(annotation.value(), element);
}
//遍历所有@BindViewClass注解
for (Element element : roundEnvironment.getElementsAnnotatedWith(BindViewClass.class)) {
BindViewClass annotation = element.getAnnotation(BindViewClass.class);
HashMap<String, Element> elementHashMap = widgets.get(annotation.groupName());
if (elementHashMap == null){
elementHashMap = new HashMap<>();
}
elementHashMap.put(annotation.value(),element);
widgets.put(annotation.groupName(), elementHashMap);
}
//生成文件
if (!widgets.isEmpty() || !fragments.isEmpty()) {
try {
annotatedHelper.createFile(fragments, widgets).writeTo(processingEnv.getFiler());
} catch (IOException e) {
e.printStackTrace();
}
}
return true;
}
@Override
public Set<String> getSupportedAnnotationTypes() {
Set<String> types = new LinkedHashSet<>();
types.add(BindFragmentClass.class.getCanonicalName());
types.add(BindViewClass.class.getCanonicalName());//手动高亮划重点 声明要处理的注解
return types;
}
}
AnnotatedHelper 辅助生成文件
注 通过
ClassName.get("java.lang", "String")
设置类型,可自动在文件中导入相关包import java.lang.String;
class AnnotatedHelper {
private static final TypeVariableName T = TypeVariableName.get("T");//定义泛型
//生成方法体
private CodeBlock.Builder getCodeBlock(HashMap<String, Element> map, int type) {
CodeBlock.Builder codeBlock = CodeBlock.builder();
codeBlock.beginControlFlow("\tswitch (name)");//这句代码之后添加"{",可单独使用 但建议与"endControlFlow"配对使用
for (String key : map.keySet()) {
Element element = map.get(key);
codeBlock.add("\t\tcase $S: ", key);
ClassName className = ClassName.get(element.getEnclosingElement().toString(), element.getSimpleName().toString());
if (type ==1){
codeBlock.addStatement("return (T) (bundle == null ? new $T() : new $T(bundle))", className, className);//这句执行之后添加";"并换行
} else {
codeBlock.addStatement("return (T) (bundle == null ? new $T(parent) : new $T(parent,bundle))", className, className);
}
}
codeBlock.addStatement("\t\tdefault: return null");
codeBlock.endControlFlow();//这句代码之前添加"}",须有前置"beginControlFlow"配对使用
return codeBlock;
}
JavaFile createFile(HashMap<String, Element> fragments, HashMap<String, HashMap<String, Element>> widgets) {
//生成方法
MethodSpec.Builder fragmentMethod = MethodSpec.methodBuilder("getFragmentInstance")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)//添加方法修饰信息
.addTypeVariable(AnnotatedHelper.T)//添加泛型
.returns(AnnotatedHelper.T)//添加方法返回类型
.addJavadoc(CodeBlock.builder().add("查找路由表获取fragment对象\n").build())//添加注释
.addCode(getCodeBlock(fragments,1).build())//添加方法体
.addParameter(ClassName.get("java.lang", "String"), "name")//添加参数 (类型 参数名)
.addParameter(ClassName.get("android.os", "Bundle"), "bundle");//添加参数 (类型 参数名)
//生成方法
ArrayList<MethodSpec.Builder> groups = null;
if (widgets != null && !widgets.keySet().isEmpty()) {
groups = new ArrayList<>();
for (String key : widgets.keySet()) {
MethodSpec.Builder widgetMethod = MethodSpec.methodBuilder(String.format("get%sInstance", key))
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addTypeVariable(AnnotatedHelper.T)
.returns(AnnotatedHelper.T)
.addCode(getCodeBlock(widgets.get(key),2).build())
.addJavadoc(CodeBlock.builder().add("查找路由表获取$S中组件对象\n",key).build())//添加注释
.addParameter(ClassName.get("java.lang", "String"), "name")
.addParameter(ClassName.get("android.view", "ViewGroup"), "parent")
.addParameter(ClassName.get("android.os", "Bundle"), "bundle");
groups.add(widgetMethod);
}
}
//生成类
TypeSpec.Builder injectClass = TypeSpec.classBuilder("Factory")//类名
.addModifiers(Modifier.PUBLIC)//类修饰符
.addJavadoc(CodeBlock.builder().add("路由表\n").build())//添加注释
// .addField(FieldSpec //添加变量
// .builder(int.class, "Version", Modifier.STATIC, Modifier.PRIVATE, Modifier.FINAL)
// .initializer("$L",1)//初始化变量
// .build())
// .addType(TypeSpec.classBuilder("累不累").build())//添加内部类
// .addAnnotation(Deprecated.class)//添加注解(方法体和变量同理)
// .addAnnotation(AnnotationSpec.builder(Target.class)//添加注解(方法体和变量同理)
// .addMember("value", "$L.TYPE",ClassName.get("java.lang.annotation", "ElementType"))
// .build())
.addMethod(fragmentMethod.build());//添加方法
if (groups != null && !groups.isEmpty()) {
for (MethodSpec.Builder build : groups) {
injectClass.addMethod(build.build());
}
}
return JavaFile.builder("指定文件包路径", injectClass.build()).build();//在指定包路径生成类文件
}
}
以上通过JavaFile相关API自动生成文件
以下通过JavaFileObject+字符串写入文件
StringBuilder builder = new StringBuilder()
.append("package com.***.view;\n\n")
.append("import android.os.Bundle;\n")
...
.append("}");
try {
JavaFileObject source = processingEnv.getFiler().createSourceFile(
"指定文件包路径.Factory");
Writer writer = source.openWriter();
writer.write(builder.toString());
writer.flush();
writer.close();
} catch (IOException e) {
//
}
app模块配置
build.gradle 本人项目中使用了kotlin所以要用kapt,没有kotlin的项目中使用annotationProcessor
apply plugin: 'kotlin-kapt'
...
dependencies {
kapt project(path: ':processor')
implementation project(path: ':annotation')
}
编译后生成的文件
package com.***.view;
import android.os.Bundle;
import android.view.ViewGroup;
import com.***.fragment.HomeFragment;
import com.***.PersonalCentreFragment;
import com.***.SmallAppManagerFragment;
import com.***.WebFragment;
import com.***.BannerVH;
import com.***.DashboardVH;
import com.***.MyAppVH;
import com.***.NotifyVH;
import com.***.WebVH;
import java.lang.String;
public class Factory {
public static <T> T getFragmentInstance(String name, Bundle bundle) {
switch (name){
case "web": return (T) (bundle == null ? new WebFragment() : new WebFragment(bundle));
case "personalCentre": return (T) (bundle == null ? new PersonalCentreFragment() : new PersonalCentreFragment(bundle));
case "subApp": return (T) (bundle == null ? new SmallAppManagerFragment() : new SmallAppManagerFragment(bundle));
case "home": return (T) (bundle == null ? new HomeFragment() : new HomeFragment(bundle));
default: return null;
}
}
public static <T> T getViewHolderInstance(String name, ViewGroup parent, Bundle bundle) {
switch (name){
case "notifyVH": return (T) (bundle == null ? new NotifyVH(parent) : new NotifyVH(parent,bundle));
case "banner": return (T) (bundle == null ? new BannerVH(parent) : new BannerVH(parent,bundle));
case "webVH": return (T) (bundle == null ? new WebVH(parent) : new WebVH(parent,bundle));
case "myApp": return (T) (bundle == null ? new MyAppVH(parent) : new MyAppVH(parent,bundle));
case "dashboard": return (T) (bundle == null ? new DashboardVH(parent) : new DashboardVH(parent,bundle));
default: return null;
}
}
}