在运行时替换字段的class(用于protostuff)

Replace the class of a field at runtime (for protostuff)

我正在研究 class 的不同版本(来自序列化二进制表示)之间的向后兼容性框架。

我坚持的一件事是如何在运行时用字段的 class 的不同版本替换 class 中使用的字段。

如果所讨论的 class 是父对象 ( Java - how to load different versions of the same class? ),我知道如何使用类加载器来完成。

但是当我已经有一个对象并且需要更改它的一个字段时(或者我不知道如何更改),这不起作用。反射 API 似乎也没有在实例化后设置 classes 的方法。

我举个例子,这样更好理解。假设我有一个包装器 class:

class Wrapper{
  int version;
  Object content;
}

现在假设 class 我加载的变量内容在 20 个版本之前发生了变化。不过,我仍然保留着当时使用的原始 .java(或 .class-)文件。我打算做的是,用旧的 class 版本的内容创建一个 wrapper 实例,从光盘加载它,转换它并将它写入一个最新版本的 wrapper 与当前版本的 class 用于内容。

它还需要非常通用,这就是为什么我在包装器中使用对象而不是实际的 class。真正的问题是我需要这个来进行 protostuff 运行时(反)序列化。这意味着我将 Wrapper.class 传递给 protostuff 并为其生成一个序列化模式。这目前失败了,因为 wrapper.class 文件自动引用了新版本(它在项目的包中)。

Schema<Wrapper> schema= RuntimeSchema.getSchema(Wrapper.class);
Wrapper resultWrapper = schema.newMessage();

我不确定这是否会通过 classloader,如果是,什么时候。我想它必须,但我不确定什么时候会发生。

解决这个问题的最佳方法是什么?

您可以做的一件事是为不同的版本设置单独的 ClassLoader 对象。由于 ClassLoader 是 class 身份的一部分,除了它的包和名称之外,您还可以在内存中拥有 class 的多个版本。这种方法的唯一问题是您最终将依赖反射来对这些对象执行任何操作。

然后您可以创建当前版本的对象并使用反射传输这些字段的值。这将解决在 运行 时间内必须修改字段类型的问题。