gpt4 book ai didi

java - 不可变业务对象和 MessagePack 消息之间的自动转换

转载 作者:塔克拉玛干 更新时间:2023-11-02 20:15:14 24 4
gpt4 key购买 nike

在 Java 中,我想使用不可变 POJO 的层次结构来表达我的领域模型。

例如

final ServiceId id = new ServiceId(ServiceType.Foo, "my-foo-service")
final ServiceConfig cfg = new ServiceConfig("localhost", 8080, "abc", JvmConfig.DEFAULT)
final ServiceInfo info = new ServiceInfo(id, cfg)

所有这些 POJO 都有没有 getter 或 setter 的公共(public)最终字段。 (如果你是 setter/getter 的粉丝,请假装这些字段是 setter/getter 私有(private)的。)

我还想使用 MessagePack 序列化这些对象库以便通过网络传递它们,将它们存储到 ZooKeeper 节点等。

问题是 MessagePack 只支持公共(public)的、非最终字段的序列化,所以我不能按原样序列化业务对象。 另外 MessagePack 不支持 enum,所以我必须将 enum 值转换为 intString 以进行序列化。 (是的,如果您向您的 enum 添加注释。请参阅下面我的评论。)

为了解决这个问题,我有一个手写的“消息”对象的相应层次结构,每个业务对象与其对应的消息对象之间都有转换。显然这并不理想,因为它会导致大量重复代码,并且人为错误可能会导致字段丢失等。

这个问题有没有更好的解决方案?

  • 在编译时生成代码?
  • 有什么方法可以在运行时生成适当的可序列化类?
  • 放弃 MessagePack?
  • 放弃业务对象中的不变性和枚举
  • 是否有某种通用包装器库可以将可变对象(消息对象)包装到不可变对象(immutable对象)(业务对象)中?

MessagePack 还支持 Java Beans 的序列化(使用 @MessagePackBeans 注释),因此如果我可以自动将不可变对象(immutable对象)与 Java Bean 相互转换,那可能会让我更接近解决方案。

最佳答案

巧合的是,我最近创建了一个几乎完全符合您描述的项目。指某东西的用途不可变数据模型提供了巨大的好处,但许多序列化技术似乎都在接近事后才想到的不变性。我想要一些可以解决这个问题的东西。

我的项目,Grains , 使用代码生成来创建不可变的实现的领域模型。该实现足够通用,可以适应不同的序列化框架。目前支持 MessagePack、Jackson、Kryo 和标准 Java 序列化。

只需编写一组描述您的域模型的接口(interface)。例如:

public interface ServiceId {
enum ServiceType {Foo, Bar}

String getName();
ServiceType getType();
}

public interface ServiceConfig {
enum JvmConfig {DEFAULT, SPECIAL}

String getHost();
int getPort();
String getUser();
JvmConfig getType();
}

public interface ServiceInfo {
ServiceId getId();
ServiceConfig getConfig();
}

Grains Maven 插件然后在编译时生成这些接口(interface)的不可变实现。(它生成的源代码旨在供人类阅读。)然后您可以创建对象的实例。这个例子展示了两种构造模式:

ServiceIdGrain id = ServiceIdFactory.defaultValue()
.withType(ServiceType.Foo)
.withName("my-foo-service");

ServiceConfigBuilder cfg = ServiceConfigFactory.newBuilder()
.setHost("localhost")
.setPort(8080)
.setUser("abc")
.setType(JvmConfig.DEFAULT);

ServiceInfoGrain info = ServiceInfoFactory.defaultValue()
.withId(id)
.withConfig(cfg.build());

不像你的 public final 字段那么简​​单,我知道,但是没有 getter 继承和组合是不可能的和二传手。而且,这些对象很容易用 MessagePack 读写:

MessagePack msgpack = MessagePackTools.newGrainsMessagePack();

byte[] data = msgpack.write(info);
ServiceInfoGrain unpacked = msgpack.read(data, ServiceInfoGrain.class);

如果 Grains 框架不适合您,请随时检查其 MessagePack templates .您可以编写一个通用的 TemplateBuilder,它使用反射来设置手写域模型的最终字段。诀窍是创建一个允许注册自定义生成器的自定义 TemplateRegistry

关于java - 不可变业务对象和 MessagePack 消息之间的自动转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7950690/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com