java - 如何找到 TypeMirror 的边界并将它们转换为 JavaPoet TypeSpec?

标签 java annotation-processing javapoet

我有一个注释处理器,它接受一个带注释的类并尝试创建它的一个子类:

package test;

import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.TypeSpec;

import java.io.IOException;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;

@SupportedAnnotationTypes("java.lang.SuppressWarnings")
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class BSProcessor extends AbstractProcessor {
    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnvironment) {
        for (TypeElement baseClassAnnotation : annotations) {
            for (Element annotatedElement : roundEnvironment.getElementsAnnotatedWith(baseClassAnnotation)) {
                handleAnnotatedTypeElement((TypeElement) annotatedElement);
            }
        }
        return true;
    }

    private void handleAnnotatedTypeElement(TypeElement annotatedTypeElement) {
        try {
            javaFile(annotatedTypeElement).writeTo(System.out);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private JavaFile javaFile(TypeElement annotatedTypeElement) {
        return JavaFile.builder(packageName(annotatedTypeElement), typeSpec(annotatedTypeElement))
                .build();
    }

    private TypeSpec typeSpec(TypeElement annotatedTypeElement) {
        return TypeSpec.classBuilder(className(annotatedTypeElement))
                .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
                .build();
    }

    private ClassName className(TypeElement annotatedTypeElement) {
        return ClassName.get(packageName(annotatedTypeElement), String.format("AutoGenerated_%s",
                annotatedTypeElement.getSimpleName()));
    }

    private String packageName(TypeElement annotatedTypeElement) {
        return annotatedTypeElement.getEnclosingElement().toString();
    }
}

这适用于没有类型参数的类,但我不确定如何使用它们。对类型变量执行 toString 只会给出变量名,而不是边界。关于如何执行此操作的任何想法?

最佳答案

TypeElement 的类型参数可以通过调用 getTypeParameters() 获取,它们的边界可以通过调用 getBounds() 获得 TypeParameterElements。我假设您对以下步骤感到困扰 — 应将哪些具体类型传递给那些类型参数以满足这些界限。

不幸的是,这是一个问题,对于任意 类型(这似乎是您所追求的)无法轻松解决。例如,看看这个类型:

public abstract class Recursive<UU extends Callable<UU>> {
}

你可能会凭直觉得出结论,它可以通过这样的类来实现:

public class Solution extends Recursive<Solution> implements Callable<Solution> {
  @Override
  public Solution call() throws Exception {
    return new Solution();
  }
}

但这对于自动化来说并非易事,而且您(可能)不想在您的代码中包含所需的机制。

与其尝试自己解决该问题,我建议您利用类型删除并让编译器为您解决问题:

// returns something like "Map<K, V>", this is NOT what you want!
DeclaredType classType = (DeclaredType) typeElement.asType();

Types types = processingEnvironment.getTypeUtils();
Elements elements = processingEnvironment.getElementUtils();

// this obtains raw type (plain "Map"), with all methods type-erased,
// the compiler is much better at solving type riddles than you!
DeclaredType rawType = types.getDeclaredType(typeElement);

final Collection<? extends ExecutableElement> methods =
    ElementFilter.methodsIn(elements.getAllMembers(typeElement));

// To create a MethodSpec, suitable for the raw type, you should 
// call 3-parameter MethodSpec#overriding with type-erased raw class type
// as second parameter and javax.lang.model.util.Types instance as third
MethodSpec newMethod = MethodSpec.overriding(methods.get(0), rawType, types);

因此,您的特定问题的答案是“不要将任何类型参数传递给 JavaPoet,使用原始类型”。

关于java - 如何找到 TypeMirror 的边界并将它们转换为 JavaPoet TypeSpec?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40586423/

相关文章:

java - kotlin 注释处理器中的可空类型

java - 如何用javapoet动态生成代码?更改方法参数

java - Java中的音频输入捕获——字节数组

java - 如何使用接口(interface)实例属性序列化类?得到 NotSerializableException

java - 如何使用 JavaPoet 生成调用父类(super class)构造函数的构造函数

JavaPoet:如何在注释中构建注释

java - 如何将两个类添加到同一个 .java 文件而不嵌套?

java - 加载包含在 .Jar 文件或类路径中的资源(图像)

java - 使用ant发布android包时编译错误

Java 11-Kotlin 注解处理器