Java注解处理器中如何解析SwitchTree表达式的类型
获取Switch表达式编译期类型的实现方案
目标是提取如下Java代码结构中switchTreeExpression的静态类型:
switch ( switchTreeExpression ) { cases }
现有代码草稿已经通过语法树遍历定位到了switch语句的表达式节点:
... MethodTree methodTree = trees.getTree(method); BlockTree blockTree = methodTree.getBody(); for (StatementTree statementTree : blockTree.getStatements()) { if (statementTree.getKind() == Tree.Kind.SWITCH) { SwitchTree switchTree = (SwitchTree) statementTree; ExpressionTree switchTreeExpression = switchTree.getExpression(); // 此处需要获取switchTreeExpression的类型 } }
已知可通过编译生成的.class文件读取类型,但不确定注解处理阶段是否能访问当前类的字节码,若可行也接受基于ObjectWeb ASM的字节码分析方案。
推荐方案:直接通过编译期Tree API获取类型(无需ASM)
不需要读取编译产物字节码,注解处理阶段可以直接通过已持有的Trees实例拿到表达式的准确类型,补全代码如下:
// 直接通过Trees工具获取表达式节点对应的类型镜像 TypeMirror switchExprType = trees.getTypeMirror(switchTreeExpression); // 后续可直接基于switchExprType做类型判断: // 比如判断是否为int/char等基本类型、是否为String、是否为枚举类、是否为允许的密封类实现等
相关注意点:
- 该API返回的是编译期解析的准确静态类型,和字节码中存储的类型完全一致,没有精度损失
- 如果需要获取泛型擦除后的类型,可以通过注解处理器上下文拿到
Types工具实例,调用types.erasure(switchExprType)即可 - 该方案实现成本最低,不需要额外引入ASM依赖,也不需要处理字节码偏移、栈帧解析等复杂逻辑
备选方案:基于ASM字节码分析获取类型
注解处理阶段可以访问到当前类的编译后字节码,只是需要注意调用时机,不要在注解处理的最早期阶段尝试读取,需要挂钩到字节码生成完成的阶段:
- 可以通过Javac插件机制注册字节码生成阶段的回调,拿到对应类的字节码数组
- 引入ASM依赖,用
ClassReader解析字节码,定位到目标方法的字节码位置 - 解析方法的栈映射帧和局部变量表,匹配switch指令对应的栈上操作数类型即可
- 该方案实现复杂度高,需要处理字节码偏移量计算、不同编译版本的class格式差异,非特殊场景不推荐使用
内容的提问来源于stack exchange,提问作者Denis
相关产品推荐
相关产品推荐

