0

我正在将 Kotlin 与 Apache Beam 一起使用,并且我有一组 DTO,它们相互引用,并且对于任何带有Kotlinx Serialization的编码器都非常适合序列化。当我尝试将它们与 Beam 一起使用时,我最终遇到了问题,因为它正在寻找所有对象、类型参数和嵌套对象来实现 JavaSerializable接口。问题是,我无法控制所有对象类型,因为有些来自 3rd-party 库。

我已经实现了我自己CustomCoder<T>的使用 Kotlinx 序列化的类型,但后来我遇到了我的自定义编码器无法序列化的问题,特别是由于 Kotlinx 序列化插件生成的伴侣对象序列化器没有序列化。由于它是编译时生成的代码,因此我无法控制它,也无法将其标记为@Transient. 我尝试Externalizable在编码器上实现,但只要我传递一个未实现的类型参数或T没有实现Serializable的嵌套类型参数,它就会失败。

此外,Kotlinx 序列化很好,因为它不使用反射。如果我能以某种方式换掉序列化机制,而不必完全依赖标准的 Java 序列化方法,或者以某种方式实现Externalizable,只需调用我自己的序列化机制并忽略类型参数。有什么解决办法吗?我不在乎它有多 hacky,即使解决方案涉及弄乱 Gradle 构建配置中的东西以覆盖某些东西。我只是不确定如何去做,所以任何指针都会有很大的帮助!

或者,如果我放弃 Kotlinx 序列化,是否有任何简单的解决方案可以使任意复杂的数据类型序列化仅适用于 Java,甚至使用反射,而无需大量定制的手动工作来处理编码和解码?我觉得也许我只是错过了一些明显的东西。这是我第一个使用 Apache Beam 的项目,但到目前为止谷歌几乎没有帮助。

4

1 回答 1

0

Mybe晚了,我最近开发了一个名为beanknife的注释处理器,它支持从任何类生成DTO。您需要通过注释进行配置。但是你不需要改变原来的类。该库支持在单独的类上进行配置。当然,您可以选择您想要的和不需要的属性。您可以通过配置类中的静态方法添加新属性。这个库最强大的功能是它支持自动将对象属性转换为 DTO 版本。例如

class Pojo1 {
    String a;
    Pojo b; // circular reference to Pojo2
}

class Pojo2 {
    Pojo1 a;
    List<Pojo1> b;
    Map<List<Pojo1>>[] c;
}

// remove the circular reference in the DTO
@ViewOf(value = Pojo1.class, includePattern = ".*", excludes={Pojo1Meta.b})
class ConfigureOfPojo2 {}

// use the no circular reference versioned dto replace the Pojo1
@ViewOf(value = Pojo2.class, includePattern = ".*")
class ConfigureOfPojo2 {
    // convert b to dto version
    @OverrideViewProperty(Pojo2Meta.b)
    private List<Pojo1View> b;
    // convert c to dto version
    @OverrideViewProperty(Pojo2Meta.c)
    private Map<List<Pojo1View>>[] c;
}

会产生

// meta class, you can use it to reference the property name in a safe way.
class Pojo1Meta {
    public final String a = "a";
    public final String b = "b";
}

// generated DTO class. The actual one will be more complicate, there are many other method.
class Pojo1View {
    private String a;
    public Pojo1View read(Pojo1 source) { ... }
    ... getters and setters ...
}

class Pojo2Meta {
    public final String a = "a";
    public final String b = "b";
    public final String c = "c";
}

class Pojo2View {
    private String a;
    private List<Pojo1View> b;
    private Map<List<Pojo1View>>[] c;
    public Pojo1View read(Pojo2 source) { ... }
    ... getters and setters ...
}

这里有趣的是您可以安全地使用源中尚不存在的类。虽然编译器可能会抱怨,但编译后一切都会好的。因为所有额外的类都会在编译之前自动生成。更好的做法可能是一步一步编译,先添加@ViewOf注解,然后编译,这样后面需要用到的类都生成了。配置完成后再次编译。这样做的好处是IDE不会有语法错误提示,可以更好的利用IDE的自动补全功能。

支持在配置类中使用生成的 DTO。您可以像示例一样定义没有循环引用的 Dto。此外,您可以为 Pojo2 定义另一个 dto,并删除所有对 Pojo1 的属性引用,并使用它来替换 Pojo1 中的属性 b。

于 2020-12-25T19:29:19.687 回答