编写一个编译时注解

最近在回看Java核心技术看到了编译时注解生成Java类并编译,手动尝试了一下

这里模仿ButterKnife写个简单的Dome记录一下,再开安卓项目比较麻烦,这里直接以字符串赋值为例

编写对应注解

@Retention(RetentionPolicy.SOURCE)//保留到源码即可
@Target(ElementType.FIELD)
public @interface Value {
    String value() default "";
}

编写对应处理器

@SupportedAnnotationTypes("com.sk.annotations.Value")//支持的注解
@SupportedSourceVersion(SourceVersion.RELEASE_8)//支持的Java版本
public class ValueProcessor extends AbstractProcessor {
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        Map<TypeElement, List<FieldInfo>> map = getFieldMap(annotations, roundEnv);
        createClassFiles(map);
        return true;//返回是否处理完毕 若处理完毕不再需要其他注解处理器处理
    }
    private void createClassFiles(Map<TypeElement, List<FieldInfo>> map) {
        for (TypeElement element : map.keySet()) {
            createClassFile(element, map.get(element));
        }
    }
    //生成对应的类文件  这里可以考虑使用模板引擎生成
    private void createClassFile(TypeElement element, List<FieldInfo> fieldInfos) {
        Messager messager = processingEnv.getMessager();
        String fullName = element.getQualifiedName().toString();
        int index = fullName.lastIndexOf('.');
        String packageName = fullName.substring(0, index);
        String name = fullName.substring(index + 1);
        String className = "Bind_" + name;
        try {
            JavaFileObject file = processingEnv.getFiler().createSourceFile(packageName + "." + className);
            Writer writer = file.openWriter();
            writer.write("package " + packageName + ";\n" +
                    "\n" +
                    "import com.sk.interfaces.ValueSetter;\n" +
                    "\n" +
                    "public class " + className + " implements ValueSetter<" + name + "> {\n" +
                    "\n" +
                    "    @Override\n" +
                    "    public void applyObject(" + name + " target) {\n");
            for (FieldInfo fieldInfo : fieldInfos) {
                writer.write("\n\ntarget." + fieldInfo.getName() + "=\"" + fieldInfo.getValue() + "\";\n");
            }
            writer.write("    }\n" +
                    "\n" +
                    "}");
            writer.close();
            messager.printMessage(Diagnostic.Kind.NOTE, "成功生成:" + fullName);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    private Map<TypeElement, List<FieldInfo>> getFieldMap(Set<? extends TypeElement> annotations,
                                                          RoundEnvironment roundEnv) {
//        Messager messager = processingEnv.getMessager();
        Map<TypeElement, List<FieldInfo>> map = new HashMap<>();
        for (TypeElement annotation : annotations) {//根据注解获取对应元素
            Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(annotation);
            for (Element element : elements) {//处理每个注解元素
                Value value = element.getAnnotation(Value.class);
                TypeElement clazz = (TypeElement) element.getEnclosingElement();
                String name = element.getSimpleName().toString();
                if (!map.containsKey(clazz)) map.put(clazz, new ArrayList<>());
                map.get(clazz).add(new FieldInfo(name, value.value()));
            }
        }
        return map;
    }
}

对应启动类

public class BindTool {
    public static void bind(Object object){
        Class<?> clazz = object.getClass();
        String fullName = clazz.getName();
        int index = fullName.lastIndexOf('.');
        try {//根据类名找对应的绑定类进行绑定
            Class<ValueSetter> bindClass = (Class<ValueSetter>) Class.forName(fullName.substring(0, index) + ".Bind_"
                    + fullName.substring(index + 1));
            ValueSetter valueSetter = bindClass.newInstance();
            valueSetter.applyObject(object);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

一些工具类省略了,最后会放上测试项目地址

配置注解处理器

在这里插入图片描述

配置Maven不注解处理该项目防止死循环

<build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.0</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <!-- Disable annotation processing for ourselves.-->
                    <compilerArgument>-proc:none</compilerArgument>
                </configuration>
            </plugin>
        </plugins>
    </build>

测试结果

在这里插入图片描述
这里实际是在编译时生成新的类并编译,并不是像lombok一样直接修改源文件
在这里插入图片描述
Dome地址:https://gitee.com/shaokang123/annotation-test

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值