- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
在 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 值转换为
int
或
String
以进行序列化。
enum
添加注释。请参阅下面我的评论。)
为了解决这个问题,我有一个手写的“消息”对象的相应层次结构,每个业务对象与其对应的消息对象之间都有转换。显然这并不理想,因为它会导致大量重复代码,并且人为错误可能会导致字段丢失等。
这个问题有没有更好的解决方案?
枚举
?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/
为什么禁用类型像 type t = A of int | B of string * mutable int 虽然允许此类类型: type t = A of int | B of string * i
我正在寻找一种类似结构的数据结构,我可以从中创建多个实例并具有某种类型提示而不是不可变的。 所以我有这样的东西: class ConnectionConfig(NamedTuple): nam
我需要转到引用的结构: class SearchKnot { var isWord : Bool = false var text : String = "" var to
如sec 10.4.3中所述 当控制进入执行时,执行以下步骤 功能对象F(调用者)中包含的功能代码的上下文 提供thisArg,而调用方提供argumentsList: 如
i make a game that start display Activity indicator And activity indicator bottom display UiLable wi
编辑:我在这里不断获得支持。只是为了记录,我认为这不再重要。自从我发布它以来我就不再需要它了。 我想在 Scala 中执行以下操作... def save(srcPath: String, destP
使用可变对象作为 Hashmap 键是一种不好的做法吗?当您尝试使用已修改足以更改其哈希码的键从 HashMap 中检索值时,会发生什么? 例如,给定 class Key { int a; /
如果您在Kotlin中访问List类型的Java值,则将获得(Mutable)List!类型。 例如。: Java代码: public class Example { public stati
我编写了 str 类(内置)的以下扩展,以便执行以下操作:假设我有字符串 "Ciao" ,通过做"Ciao" - "a"我想要的结果是字符串 "Cio" 。这是执行此操作的代码,并且运行良好: cla
使用可变对象作为 Hashmap 键是一种不好的做法吗?当您尝试使用已修改足以更改其哈希码的键从 HashMap 中检索值时,会发生什么? 例如,给定 class Key { int a; /
我正在为我的公司设计一个数据库来管理商业贷款。每笔贷款都可以有担保人,可以是个人或公司,在借款业务失败时作为财务支持。 我有 3 个表:Loan、Person 和 Company,它们存储明显的信息。
我使用二进制序列化从 C# 类中保存 F# 记录。一切正常: F#: type GameState = { LevelStatus : LevelStatus
import javax.swing.JOptionPane; public class HW { public static void main(String[] args) { Strin
使用 flatbuffer mutable 有多少性能损失? 是否“正确”使用 FlatBuffers 来拥有一个应该可编辑的对象/结构(即游戏状态) 在我的示例中,我现在有以下类: class Ga
std::function create_function (args...) { int x = initial_value (args...); return [x] () mut
我需要在 for 循环中找到用户输入的字符。我通常会这样做 如果(句子[i] == 'e') 但是因为在这里,'e' 将是一个单字母字符变量,我不知道如何获取要比较的值。我不能只输入 if (sent
我有一个这样的算法: let seed: Foo = ... let mut stack: Vec = Vec::new(); stack.push(&seed); while let Some(ne
这个问题可能看起来非常基础,但我很难弄清楚如何做。我有一个整数,我需要使用 for 循环来循环整数次。 首先,我尝试了—— fn main() { let number = 10; // An
如果我有以下结构: struct MyStruct { tuple: (i32, i32) }; 以及以下函数: // This will not compile fn function(&mut s
我希望在每个 session 的基础上指定列的默认值。下面的脚本不起作用,但描述了我想如何使用它。我目前使用的是 MySQL 5.5.28,但如果需要可以升级。 CREATE TABLE my_tbl
我是一名优秀的程序员,十分优秀!