• 最新
  • 热门
  • 所有
  • 外汇
  • 24 小时
  • 期货
  • 基金
  • 贵金属
  • 股票
xiuyuantech 博客 - 注解处理器 APT (Annotation Processing Tool)

xiuyuantech 博客 - 注解处理器 APT (Annotation Processing Tool)

2025 年 12 月 12 日
涨停潮!英伟达「缺电大会」引爆 主力盯上这些票(名单)

涨停潮!英伟达 「缺电大会」 引爆 主力盯上这些票 (名单)

2025 年 12 月 12 日
小米17 Ultra本月发布实锤:搭载国产一英寸旗舰影像

小米 17 Ultra 本月发布实锤:搭载国产一英寸旗舰影像

2025 年 12 月 12 日
十四届全国人大常委会第十八次会议10月24日至28日将在京举行

国资委:靠前推动一批重大项目落实落地 中央企业要自觉抵制 「内卷式」 竞争

2025 年 12 月 12 日
广告

华西证券:明年债市或比预期好一点 行情节奏可能靠后

2025 年 12 月 12 日

通信 ETF 跌近 4%

2025 年 12 月 12 日
十四届全国人大常委会第十八次会议10月24日至28日将在京举行

「鹰派风暴」 即将来袭?消息人士:日本央行下周加息板上钉钉 更多鹰声已在路上

2025 年 12 月 12 日
再次提醒:中国公民近期避免前往日本!中使馆:请在日中国公民进行登记

再次提醒:中国公民近期避免前往日本!中使馆:请在日中国公民进行登记

2025 年 12 月 12 日
商品日报(12月12日):金属板块全面活跃!锡盘中涨超6% 银铜同创历史新高

商品日报 (12 月 12 日):金属板块全面活跃!锡盘中涨超 6% 银铜同创历史新高

2025 年 12 月 12 日
十四届全国人大常委会第十八次会议10月24日至28日将在京举行

央行:继续实施适度宽松的货币政策 坚定维护金融市场平稳运行

2025 年 12 月 12 日
何小鹏打赌:小鹏VLA未来能否实现特斯拉FSD V14.2全部能力?

何小鹏打赌:小鹏 VLA 未来能否实现特斯拉 FSD V14.2 全部能力?

2025 年 12 月 12 日

开源证券:高度看好商业航天的投资机遇

2025 年 12 月 12 日

80 多艘恐被困、30 多艘恐被扣押!警惕美国扣押油轮引爆委内瑞拉出口危机

2025 年 12 月 12 日
金桂财经
广告
2025 年 12 月 12 日 星期五
联系我们
合作建议
  • 首页
  • 24 小时
  • 全球金融
  • 股市风云
  • 基金动态
  • 金财眼
  • 期货新闻
  • 期货研报
  • 外汇市场
  • 贵金属
  • 未来科技
  • 登录& 注册
没有结果
查看所有结果
  • 首页
  • 24 小时
  • 全球金融
  • 股市风云
  • 基金动态
  • 金财眼
  • 期货新闻
  • 期货研报
  • 外汇市场
  • 贵金属
  • 未来科技
没有结果
查看所有结果
金桂财经
没有结果
查看所有结果

xiuyuantech 博客 - 注解处理器 APT (Annotation Processing Tool)

来自 金桂财经
2025 年 12 月 12 日
在 科技
0

xiuyuantech 博客: https://xiuyuantech.github.io/

YOU MAY ALSO LIKE

脉脉发布 2025 年度人才报告,1-10 月新发 AI 岗位量同比攀升 543%

找 Coze 工作流绕了 3 个群?这个免费网站直接打包 200+,还能薅 Sora2 和 Banana Pro 插件

注解处理器是一种处理注解的工具,确切的说它是 javac 的一个工具,它用来在编译时扫描和处理注解。
注解处理器以 Java 代码 (或者编译过的字节码) 作为输入, 生成.java 文件作为输出, 减少手动的代码输入。
简单来说就是在编译期, 通过注解生成.java 文件。比如我们经常用的轮子 Dagger2, ButterKnife,
EventBus 都在用,我们要紧跟潮流来看看 APT 技术的来龙去脉。

实现方式
创建 Android Module 命名为 app
创建 Java library Module 命名为 apt-annotation
创建 Java library Module 命名为 apt-processor 依赖 apt-annotation
创建 Android library Module 命名为 apt-library 依赖 apt-annotation、auto-service
可选 compileOnly files(org.gradle.internal.jvm.Jvm.current().getToolsJar())

注意不可都放在一个 Module 中,放在一个 Module 中不会生效!

功能主要分为三个部分

apt-annotation:存放自定义注解
apt-processor:注解处理器,根据 apt-annotation 中的注解,在编译期生成 xxx.java 代码
apt-library:工具类,实现业务逻辑的绑定。

结构图

apt-annotation (自定义注解)

@Retention(RetentionPolicy.CLASS):表示编译时注解
@Target(ElementType.FIELD):表示注解范围为类成员 (构造方法、方法、成员变量)

@Retention: 定义被保留的时间长短
RetentionPoicy.SOURCE、RetentionPoicy.CLASS、RetentionPoicy.RUNTIME
@Target: 定义所修饰的对象范围
TYPE、FIELD、METHOD、PARAMETER、CONSTRUCTOR、LOCAL_VARIABLE 等

apt-processor (注解处理器)

添加依赖

dependencies {
    implementation project(':apt-annotation')
    implementation 'com.google.auto.service:auto-service:1.0-rc4'
    annotationProcessor 'com.google.auto.service:auto-service:1.0-rc4'
    compileOnly files(org.gradle.internal.jvm.Jvm.current().getToolsJar()) //optional
}

自定义处理器 BindViewProcessor

@AutoService(Processor.class)
public class BindViewProcessor extends AbstractProcessor {

    private Messager messager;
    private Trees trees;
    private TreeMaker maker;
    private Name.Table names;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        messager = processingEnv.getMessager();
        trees = Trees.instance(processingEnv);
        Context context = ((JavacProcessingEnvironment) processingEnv).getContext();
        maker = TreeMaker.instance(context);
        names = Names.instance(context).table;
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        if (!roundEnv.processingOver()) {
            Set<? extends Element> elements = roundEnv.getRootElements();
            for (Element each : elements) {
                if (each.getKind() == ElementKind.CLASS) {
                    JCTree tree = (JCTree) trees.getTree(each);
                    if (tree != null) {
                        if (tree instanceof JCTree.JCClassDecl) {
                            if (((JCTree.JCClassDecl) tree).name.toString().equals(
                                    "WebAppInterface")) {
                                tree.accept(new Insert(messager, maker, names));
                                break;
                            }
                        }
                    }
                }
            }
        }
        return false;
    }

    class Insert extends TreeTranslator {
        private Messager messager;
        private TreeMaker maker;
        private Name.Table names;

        public Insert(Messager messager, TreeMaker maker, Name.Table names) {
            this.messager = messager;
            this.maker = maker;
            this.names = names;
        }

        @Override
        public void visitMethodDef(JCTree.JCMethodDecl jcMethodDecl) {
            super.visitMethodDef(jcMethodDecl);
            boolean isVisited = false;
            if (jcMethodDecl.mods != null && jcMethodDecl.mods.annotations != null) {
                List<JCTree.JCAnnotation> ans = jcMethodDecl.mods.annotations;
                for (JCTree.JCAnnotation annotation : ans) {
                    if (annotation.annotationType.toString().equals("JavascriptInterface")) {
                        isVisited = true;
                        break;
                    }
                }
            }
            if (isVisited) {
                JCTree.JCExpression invokeMethod = maker.Apply(List.nil(),
                        maker.Select(maker.Ident(names.fromString("mWebActivity")),
                                names.fromString(
                                        "getCurrentUrl")), List.nil());
                JCTree.JCVariableDecl statement = makeVarDef(maker.Modifiers(0), "surl",
                        memberAccess("java.lang.String"), invokeMethod);
                JCTree.JCExpression invokeMethod1 = maker.Apply(List.of(memberAccess("java.lang" +
                                ".String"), memberAccess("java.lang.String")),
                        memberAccess("com.dxdxmm.app.component.web.WebBridgeHelperKt" +
                                ".isHostVerify"), List.of(maker.Ident(names.fromString("surl")),
                                maker.Literal(jcMethodDecl.name.toString())));
                JCTree.JCVariableDecl statement1 = makeVarDef(maker.Modifiers(0), "verify",
                        maker.TypeIdent(TypeTag.BOOLEAN), invokeMethod1);
                JCTree.JCIf statement2 = maker.If(maker.Ident(names.fromString("verify")),
                        jcMethodDecl.body, maker.Skip());
                JCTree.JCReturn statement3 = maker.Return(maker.Literal(false));
                JCTree.JCReturn statement4 = maker.Return(maker.Literal(""));

                ListBuffer<JCTree.JCStatement> statements = new ListBuffer<>();
                if (!jcMethodDecl.name.toString().equals("<init>")) {
                    statements.append(statement);
                    statements.append(statement1);
                    statements.append(statement2);
                    if (jcMethodDecl.restype != null) {
                        if (jcMethodDecl.restype.toString().equals("String")) {
                            statements.append(statement4);
                        } else if (jcMethodDecl.restype.toString().equals("boolean")) {
                            statements.append(statement3);
                        }
                    }
                }
                JCTree.JCBlock body = maker.Block(0, statements.toList());
                result = maker.MethodDef(
                        jcMethodDecl.getModifiers(),
                        names.fromString(jcMethodDecl.name.toString()),
                        jcMethodDecl.restype,
                        jcMethodDecl.typarams,
                        jcMethodDecl.params,
                        jcMethodDecl.thrown,
                        body,
                        jcMethodDecl.defaultValue
                );
                note(result.toString());
            }
        }

        private JCTree.JCVariableDecl makeVarDef(JCTree.JCModifiers modifiers, String name,
                                                 JCTree.JCExpression vartype,
                                                 JCTree.JCExpression init) {
            return maker.VarDef(
                    modifiers,
                    names.fromString(name),
                    vartype,
                    init
            );
        }

        private JCTree.JCExpression memberAccess(String components) {
            String[] componentArray = components.split("\\.");
            JCTree.JCExpression expr = maker.Ident(names.fromString(componentArray[0]));
            for (int i = 1; i < componentArray.length; i++) {
                expr = maker.Select(expr, names.fromString(componentArray[i]));
            }
            return expr;
        }
    }

    private void note(String msg) {
        messager.printMessage(Diagnostic.Kind.NOTE, msg);
    }

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        HashSet<String> supportTypes = new LinkedHashSet<>();
        supportTypes.add(WebModule.class.getCanonicalName());
        return supportTypes;
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }
}

init:初始化。可以得到 ProcessingEnviroment,ProcessingEnviroment 提供很多有用的工具类 Elements, Types 和 Filer
getSupportedAnnotationTypes:指定这个注解处理器是注册给哪个注解的,这里说明是注解 BindView
getSupportedSourceVersion:指定使用的 Java 版本,通常这里返回 SourceVersion.latestSupported()
process:可以在这里写扫描、评估和处理注解的代码,生成 Java 文件

Messager : 日志打印类,有利于分析
Trees : 抽象语法树
TreeMaker : 抽象语法树操作类
Name.Table : 命名表, 可根据名称找到对应的方法,变量,类
TreeTranslator : 抽象语法树转换器, 可修改方法,变量,类

其他类不熟悉的自行查询,这里就不一一介绍了。

完成了 Processor 的部分,基本就大功告成了。

apt-library 工具类 可选

在 App Module 的 build.gradle 中添加依赖

dependencies {
    implementation project(':apt-annotation')
}

创建注解工具类 BindViewTools

public class BindViewTools {

    public static void bind(Activity activity) {

        Class clazz = activity.getClass();
        try {
            Class bindViewClass = Class.forName(clazz.getName() + "_ViewBinding");
            Method method = bindViewClass.getMethod("bind", activity.getClass());
            method.invoke(bindViewClass.newInstance(), activity);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}
```java
通过 javapoet 生成代码:

添加依赖
```java
dependencies {
    implementation 'com.squareup:javapoet:1.10.0'
}

新建 ClassCreatorProxy

public class ClassCreatorProxy {
    //省略部分代码...

    /**
     * 创建 Java 代码
     * @return
     */
    public TypeSpec generateJavaCode2() {
        TypeSpec bindingClass = TypeSpec.classBuilder(mBindingClassName)
                .addModifiers(Modifier.PUBLIC)
                .addMethod(generateMethods2())
                .build();
        return bindingClass;

    }

    /**
     * 加入 Method
     */
    private MethodSpec generateMethods2() {
        ClassName host = ClassName.bestGuess(mTypeElement.getQualifiedName().toString());
        MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder("bind")
                .addModifiers(Modifier.PUBLIC)
                .returns(void.class)
                .addParameter(host, "host");

        for (int id : mVariableElementMap.keySet()) {
            VariableElement element = mVariableElementMap.get(id);
            String name = element.getSimpleName().toString();
            String type = element.asType().toString();
            methodBuilder.addCode("host." + name + " = " + "(" + type + ")(((android.app.Activity)host).findViewById( " + id + "));");
        }
        return methodBuilder.build();
    }


    public String getPackageName() {
        return mPackageName;
    }
}

使用自定义注解

使用工具类时:

public class TestActivity extends AppCompatActivity {

    @BindView(R.id.test)
    TextView textView;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test);
        BindViewTools.bind(this);
    }

}

不使用工具类, 只修改某个方法时:

@BindView()
public class TestActivity extends AppCompatActivity {

    TextView textView;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test);
    }

    @JavascriptInterface
    public void test(){

    }
}

业务咨询:https://soloist.pages.dev

文章来源:w2solo

Search

没有结果
查看所有结果

一周热门

涨停潮!英伟达「缺电大会」引爆 主力盯上这些票(名单)

涨停潮!英伟达 「缺电大会」 引爆 主力盯上这些票 (名单)

2025 年 12 月 12 日
小米17 Ultra本月发布实锤:搭载国产一英寸旗舰影像

小米 17 Ultra 本月发布实锤:搭载国产一英寸旗舰影像

2025 年 12 月 12 日
十四届全国人大常委会第十八次会议10月24日至28日将在京举行

国资委:靠前推动一批重大项目落实落地 中央企业要自觉抵制 「内卷式」 竞争

2025 年 12 月 12 日

华西证券:明年债市或比预期好一点 行情节奏可能靠后

2025 年 12 月 12 日

通信 ETF 跌近 4%

2025 年 12 月 12 日
十四届全国人大常委会第十八次会议10月24日至28日将在京举行

「鹰派风暴」 即将来袭?消息人士:日本央行下周加息板上钉钉 更多鹰声已在路上

2025 年 12 月 12 日
再次提醒:中国公民近期避免前往日本!中使馆:请在日中国公民进行登记

再次提醒:中国公民近期避免前往日本!中使馆:请在日中国公民进行登记

2025 年 12 月 12 日
商品日报(12月12日):金属板块全面活跃!锡盘中涨超6% 银铜同创历史新高

商品日报 (12 月 12 日):金属板块全面活跃!锡盘中涨超 6% 银铜同创历史新高

2025 年 12 月 12 日
十四届全国人大常委会第十八次会议10月24日至28日将在京举行

央行:继续实施适度宽松的货币政策 坚定维护金融市场平稳运行

2025 年 12 月 12 日
何小鹏打赌:小鹏VLA未来能否实现特斯拉FSD V14.2全部能力?

何小鹏打赌:小鹏 VLA 未来能否实现特斯拉 FSD V14.2 全部能力?

2025 年 12 月 12 日
金桂财经

2025 年 12 月
一 二 三 四 五 六 日
1234567
891011121314
15161718192021
22232425262728
293031  
« 11 月    

近期动态

  • 涨停潮!英伟达 「缺电大会」 引爆 主力盯上这些票 (名单)
  • 小米 17 Ultra 本月发布实锤:搭载国产一英寸旗舰影像
  • 国资委:靠前推动一批重大项目落实落地 中央企业要自觉抵制 「内卷式」 竞争
  • 华西证券:明年债市或比预期好一点 行情节奏可能靠后
  • 通信 ETF 跌近 4%
  • 「鹰派风暴」 即将来袭?消息人士:日本央行下周加息板上钉钉 更多鹰声已在路上
广告

Copyright © 2025 广州金桂广告传媒有限公司. 粤 ICP 备 2025390655 号

  • 关于本站
  • 联系我们
  • 隐私政策
没有结果
查看所有结果
  • 登录& 注册

Copyright © 2025 广州金桂广告传媒有限公司. 粤 ICP 备 2025390655 号

  • 登录
  • 注册
忘记密码?
Lost your password? Please enter your username or email address. You will receive a link to create a new password via email.
body::-webkit-scrollbar { width: 7px; } body::-webkit-scrollbar-track { border-radius: 10px; background: #f0f0f0; } body::-webkit-scrollbar-thumb { border-radius: 50px; background: #dfdbdb }