【问题标题】:How to add a parameterized super interface in JavaPoet?JavaPoet中如何添加参数化的超接口?
【发布时间】:2020-04-12 01:11:38
【问题描述】:

我正在编写一个生成 JSON 序列化代码的注释处理器。这是我用来识别需要序列化程序的POJOs 的注释

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface JsonSerialize {

}

这是我的序列化程序的基本接口

public interface JsonSerializer<T> {

    String serialize(T t);

}

这是查找该注释并生成序列化程序代码的注释处理器代码

@Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        for (Element element : roundEnv.getElementsAnnotatedWith(JsonSerialize.class)) {
            if (element.getKind() == ElementKind.CLASS) {

                MethodSpec serializeMethod = MethodSpec
                        .methodBuilder("serialize")
                        .addModifiers(Modifier.PUBLIC)
                        .addParameter(ParameterSpec.builder(TypeName.get(element.asType()), "obj", Modifier.FINAL).build())
                        .returns(String.class)
                        .addStatement("return \"dummy string\"")
                        .build();

                TypeSpec serializer = TypeSpec
                        .classBuilder(element.getSimpleName().toString() + "JsonSerializer")
                        .addSuperinterface(JsonSerializer.class) // THIS LINE IS WRONG
                        .addModifiers(Modifier.PUBLIC)
                        .addMethod(serializeMethod)
                        .build();

                try {
                    JavaFile.builder(processingEnv.getElementUtils().getPackageOf(element).toString(), serializer)
                            .build()
                            .writeTo(processingEnv.getFiler());
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
        }
        return true;
    }

但是我得到一个编译错误,因为我生成的类没有在它的继承中指定泛型参数。我该如何指定?

【问题讨论】:

    标签: java annotation-processing javapoet


    【解决方案1】:

    您需要传递一些包含您想到的特定类型详细信息的东西,而不是将 java.lang.Class 传递给 addSuperinterface 方法。此方法有两个重载 - 一个采用 java.lang.reflect.TypeClass 是 this 的子类型),另一个采用 com.squareup.javapoet.TypeName)。从技术上讲,这两种方法都可以,但由于您已经在使用 JavaPoet,我建议您尝试创建 TypeName 实例。

    TypeName 有许多子类,ClassNameParameterizedTypeName 可能是这里重点关注的主要类。在注释处理器中,与使用 Class 实例相比,它们具有一些很大的优势 - 主要是您实际上不需要能够加载或引用您正在谈论的类 - 有点像您使用 element.getSimpleName().toString() 的方式代码中的其他位置。

    这些类具有创建它们的静态方法,这些方法可以基于多种事物。我们在这里感兴趣的是:

      /** Returns a parameterized type, applying {@code typeArguments} to {@code rawType}. */
      public static ParameterizedTypeName get(ClassName rawType, TypeName... typeArguments)
    

    在你的代码中,你会大致这样使用它:

        ...
        .addSuperinterface(ParameterizedTypeName.get(
                ClassName.get(JsonSerializer.class),//rawType
                ClassName.get(whateverTShouldBe)    //the value for T
        ))
        ...
    

    T 最终在这里也可能是通用的,就像List&lt;String&gt;,所以你应该注意正确构建在那里传递的类型 - 它本身可能是ParameterizedTypeName。请注意 TypeName 中的各种方法 - 例如,TypeName.get(TypeMirror) 重载将采用已参数化的声明类型镜像,并再次返回预期的 ParameterizedTypeName

    话虽如此,根据您的其他代码,今天的T 不能是通用的-您在Element 上查找@JsonSerialize 注释,这意味着它将等同于List&lt;T&gt; 而不是用法其中,List&lt;String&gt;。然后,在这一行中,您将 Element 设为 TypeMirror 以构建类型名称,如上所述:

        .addParameter(ParameterSpec.builder(TypeName.get(element.asType()), "obj", Modifier.FINAL).build())
    

    这意味着最终的代码可能是

        ...
        .addSuperinterface(ParameterizedTypeName.get(
                ClassName.get(JsonSerializer.class),//rawType
                TypeName.get(element.asType())    //the value for T
        ))
        ...
    

    【讨论】:

      猜你喜欢
      • 2015-09-07
      • 1970-01-01
      • 2018-02-14
      • 2018-03-03
      • 1970-01-01
      • 2018-02-06
      • 1970-01-01
      • 2015-05-20
      • 2017-06-14
      相关资源
      最近更新 更多