Java序列化:readFields()超出了readObject()?

6

ObjectInputStream.readFields() 只能在 private void readObject(ObjectInputStream) 方法内使用。

public ObjectInputStream.GetField readFields() throws IOException, ClassNotFoundException {
  SerialCallbackContext ctx = curContext;
  if (ctx == null) {
    throw new NotActiveException("not in call to readObject");
  }
...

我现在的情况是无法使用默认的序列化方式来读取对象(例如ObjectInputStream.defaultReadObject()),但我又不想在所有类中实现readObject()方法。在理想情况下,我希望有一个ownDefaultReadObject()方法,可以通过反射从序列化的字段构建新的对象。
您有什么好的想法吗?
如果有人想了解更多信息。我的某些类中的字段名称已被重命名(例如通过模糊器)。这些类是使用默认的Java序列化方式进行序列化的,需要将它们反序列化为原始类(我知道每个类的字段名称对应关系;例如a => fieldName,b => age,c => gender等)。

你的愿望是一回事,但你不实现readObject()原因是什么? - user207421
@EJP 16: 我有几百个这样的类。它们可能会在未来被添加/删除。我不希望开发团队中的任何人甚至考虑序列化/反序列化问题。我有一个选项,可以在构建过程中使用字节码注入(例如Javassist)来添加readObject()方法,但我想使用更简单的解决方案。 - FoxyBOA
@biziclop:是的,我正在考虑这种解决方案,但希望能有更简单的方法通过字节码插装实现。 - FoxyBOA
@FoxyBOA,我想说可能没有更简单的解决方案。但这只是基于序列化通常的工作方式的猜测,也许有一个不太可能的钩子可以附加到这个逻辑上。 - biziclop
@biziclop:另一个(可能更简单)的解决方案是为了Kryo(https://code.google.com/p/kryo/wiki/V1Benchmarks)、XStream(http://x-stream.github.io)或其他轻量级序列化库而不使用Java序列化。 - FoxyBOA
显示剩余6条评论
1个回答

1
要重命名对象流中的字段,您需要覆盖的方法是ObjectInputStream.readClassDescriptor,该方法返回一个ObjectStreamClassObjectStreamClass实例通过接口的大不同子集来执行两种不同的角色。为了避免疑问,不应复制此设计选择。
  • 描述在当前JVM实例中运行的可序列化类的字段。通过ObjectStreamClass.lookup查找这些实例。
  • 描述在特定序列化流中表示的可序列化类的字段。这些实例由ObjectInputStream.readClassDescriptor的实现返回。
在您的覆盖中调用super.readClassDescriptor。这将从流中读取数据。如果您感兴趣的是类,则用具有新字段名称的值替换来自流的值。
如何创建自己的ObjectStreamClass?将您感兴趣的类的虚拟实例写入ObjectOutputStream。您可以将其作为构建的一部分完成,只需保留二进制数据即可。使用另一个带有覆盖readClassDescriptorObjectInputStream进行读取以存储描述符。

ObjectInputStream.defaultReadObject/readFields 没有在 readObject(或类似方法)之外的任何地方意义,因为它们依赖于当前反序列化对象而不是参数。还有其他限制,防止其他代码调用 defaultReadObject 重写必须保持恒定,复制验证,安全检查或类似的字段。


我本来想写一些代码来完成这个任务,但是我现在正在做其他的事情。对于原帖和Java序列化来说可能有点晚了。/(我最初在错误的问题上发布了这个答案,因为我很蠢。) - Tom Hawtin - tackline
你可以使用反射来赋值变量,查看我的解决方案。 - Archmede

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接