【问题标题】:How to serialize Java ZonedDateTime to XML file如何将 Java ZonedDateTime 序列化为 XML 文件
【发布时间】:2019-11-11 22:34:40
【问题描述】:

序列化 ZonedDateTime 时出错(它根本没有出现在输出 xml 中):

java.lang.InstantiationException: java.time.ZonedDateTime

继续...

java.lang.RuntimeException:评估失败:=Class.new();

继续...

我有一个类的实例,其中一个字段属于 ZonedDateTime 类型。 当我尝试使用 XMLEncoder 序列化对象时:

import java.beans.XMLEncoder;

我收到此错误。在输出文件中,除了 ZonedDateTime 字段之外,所有其他字段都会出现

这个带有 ZonedDateTime 的字段看起来像这样,例如:

ZonedDateTime date = ZonedDateTime.parse("2010-01-10T00:00:00Z[CET]");

有没有办法将其转换为可以使用的日期格式? 例如

ZonedDateTime.parse("2010-01-10T00:00:00").toLocalDateTime().atZone(ZoneId.of("CET")

上面的写法(用.toLocalDateTime())可能没有任何意义,但这只是一个例子。

我实际上是在序列化这些对象的整个列表,所以错误出现了很多次(并且总是在 xml 文件中没有输出)

【问题讨论】:

  • "2010-01-10T00:00:00" 不是ZonedDateTime。它没有时区,因此您必须直接将其解析为LocalDateTime
  • 为什么不LocalDateTime.parse(yourString).atZone(ZoneId.of("CET"))
  • 在序列化或反序列化过程中是否出现错误?您的错误表明它无法使用它的构造函数实例化 ZonedDateTime(这是正确的 - 它需要调用 parse 方法,并且您可能需要某种类型的适配器用于 XML 解析器)。但您不会在 ser 序列化期间收到该错误,因为它不需要在序列化期间创建实例。
  • @ErwinBolwidt 我在尝试序列化时遇到了这个问题(即从程序写入 output.xml 文件)。
  • @AndyTurner 所以你的意思是这样的: ZonedDateTime date = LocalDateTime.parse(DateInString).atZone(ZoneId.of("CET")) ?我想我已经尝试过了,但会再试一次

标签: java hibernate serialization xmlencoder


【解决方案1】:

XMLEncoder 和 XMLDecoder 旨在与常规 Java bean 类一起工作。通常,这些是具有公共零参数构造函数和公共属性访问器方法的类。对其他类有一些支持,例如那些具有采用属性值的构造函数的类,但大多数 java.time 类是不同的,并且没有对它们的内置支持。

幸运的是,您可以通过 specifying a PersistenceDelegate 为您计划序列化的每个非 Java-bean 类提供自己的支持。

所以,第一步是为 ZonedDateTime 提供 PersistenceDelegate:

PersistenceDelegate zonedDateTimeDelegate = new PersistenceDelegate() {
    @Override
    protected Expression instantiate(Object target,
                                     Encoder encoder) {
        ZonedDateTime other = (ZonedDateTime) target;
        return new Expression(other, ZonedDateTime.class, "of",
            new Object[] {
                other.getYear(),
                other.getMonthValue(),
                other.getDayOfMonth(),
                other.getHour(),
                other.getMinute(),
                other.getSecond(),
                other.getNano(),
                other.getZone()
            });
    }
};

encoder.setPersistenceDelegate(
    ZonedDateTime.class, zonedDateTimeDelegate);

但事实证明这还不够,因为 ZonedDateTime 的部分也被序列化,其中之一是 ZoneId。所以我们还需要一个用于 ZoneId 的 PersistenceDelegate。

PersistenceDelegate 很容易写:

PersistenceDelegate zoneIdDelegate = new PersistenceDelegate() {
    @Override
    protected Expression instantiate(Object target,
                                     Encoder encoder) {
        ZoneId other = (ZoneId) target;
        return new Expression(other, ZoneId.class, "of",
            new Object[] { other.getId() });
    }
};

但是注册它并不容易。 encoder.setPersistenceDelegate(ZoneId.class, zoneIdDelegate); 不起作用,因为 ZoneId 是一个抽象类,这意味着没有 ZoneId 对象,只有子类的实例。 XMLEncoder 在检查 PersistenceDelegates 时不咨询继承。每个要序列化的对象的每个类都必须有一个 PersistenceDelegate。

如果你只序列化一个 ZonedDateTime,解决方案很简单:

encoder.setPersistenceDelegate(
    date.getZone().getClass(), zoneIdDelegate);

如果你有它们的集合,你可以检查它们所有的 ZoneId 类:

Set<Class<? extends ZoneId>> zoneClasses = new HashSet<>();
for (ZonedDateTime date : dates) {
    Class<? extends ZoneId> zoneClass = date.getZone().getClass();
    if (zoneClasses.add(zoneClass)) {
        encoder.setPersistenceDelegate(zoneClass, zoneIdDelegate);
    }
}

如果您有包含 ZonedDateTimes 的聚合对象,您可以简单地以类似方式遍历它们并访问这些 ZonedDateTime 值。

【讨论】:

  • 好的,从文件获取信息到程序时如何解码?
  • 只需使用XMLDecoder。无需自定义。
猜你喜欢
  • 2019-06-18
  • 2018-11-20
  • 1970-01-01
  • 2011-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多