Java注解处理器中使用TypeVisitor访问返回值接口的方案咨询
开发注解处理器时,我需要筛选所有返回实现特定接口的Record类型的方法。调试阶段在IntelliJ窗口看到restype变量包含interfaces_field字段,可通过它获取返回值的ClassType,但构建时直接访问该变量会触发报错:
e: file:///home/thomas/IdeaProjects/spring-view-component/core/src/main/kotlin/de/tschuehly/spring/viewcomponent/core/processor/ViewComponentProcessor.kt:3:33
Symbol is declared in module 'jdk.compiler' which does not export package 'com.sun.tools.javac.code'
这是因为直接访问了JDK内部未导出的com.sun.tools.javac.code包——这类非公开API在构建时会被限制调用,不能作为生产代码的依赖。正确的做法是使用javax.lang.model提供的公开API,结合TypeVisitor来实现需求,以下是具体步骤:
具体实现方案
1. 判断返回类型是否为Record类型
通过TypeMirror的accept方法,结合SimpleTypeVisitor6(JDK提供的TypeVisitor默认实现)来识别Record类型:
private fun isRecordType(type: TypeMirror): Boolean { return type.accept(object : SimpleTypeVisitor6<Boolean, Void>() { override fun visitDeclared(t: DeclaredType, p: Void?): Boolean { val element = t.asElement() as? TypeElement return element?.kind == ElementKind.RECORD } override fun defaultAction(e: TypeMirror?, p: Void?): Boolean { return false } }, null) }
2. 检查Record是否实现目标接口
拿到返回类型对应的TypeElement后,遍历其所有接口(包括父接口),判断是否包含目标接口:
private fun implementsTargetInterface(recordElement: TypeElement, targetInterface: TypeElement): Boolean { val typeUtils = processingEnv.typeUtils // 遍历Record的直接接口 for (interfaceType in recordElement.interfaces) { if (typeUtils.isAssignable(interfaceType, targetInterface.asType())) { return true } // 递归检查父接口(如需处理接口继承场景) val interfaceElement = interfaceType.asElement() as TypeElement if (implementsTargetInterface(interfaceElement, targetInterface)) { return true } } return false }
3. 整合筛选逻辑
在注解处理器中遍历方法元素,结合上述两个方法完成筛选:
fun processMethods(elements: Set<Element>) { val targetInterface = processingEnv.elementUtils.getTypeElement("com.yourpackage.YourTargetInterface") ?: error("目标接口未找到") for (element in elements) { if (element.kind == ElementKind.METHOD) { val method = element as ExecutableElement val returnType = method.returnType // 先判断返回类型是否为Record if (!isRecordType(returnType)) continue // 获取Record对应的TypeElement val recordElement = (returnType as DeclaredType).asElement() as TypeElement // 检查是否实现目标接口 if (implementsTargetInterface(recordElement, targetInterface)) { // 对符合条件的方法执行后续逻辑 println("找到符合条件的方法: ${method.simpleName}") } } } }
核心注意点
- 全程使用
javax.lang.model下的公开API(TypeMirror、DeclaredType、TypeUtils等),完全避免依赖JDK内部未公开的类和字段,保证代码的兼容性与可移植性。 SimpleTypeVisitor6仅需重写需要处理的类型分支(比如DeclaredType对应类/接口类型),其他类型走默认逻辑即可,代码简洁且符合规范。
内容的提问来源于stack exchange,提问作者tschuehly

