为 ZonedDateTime 编写 xstream 转换器

Writing xstream Converter for ZonedDateTime

为了从日历更改为 ZonedDateTime (java.time),我必须为 xstream 编写 ZonedDateTime 转换器。 在这篇文章中 https://github.com/x-stream/xstream/issues/24 被建议

What you can actually do is writing a custom converter for ZonedDateTime where the type is represented as String. Use this String representation to convert back into a ZonedDateTime instance.<<

我尝试了两种方法:第一种是扩展 com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter,第二种是实现 com.thoughtworks.xstream.converters.Converter

这是第二种方法的代码:

public class ZonedDateTimeConverter implements Converter
{
@Override
public boolean canConvert(Class type)
{
  return (type != null) && (ZonedDateTime.class.equals(type));
}
@Override
public void marshal(Object source, HierarchicalStreamWriter writer,
     MarshallingContext context)
{
  ZonedDateTime zonedDateTime = (ZonedDateTime) source;
  writer.setValue(zonedDateTime.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));  
}

@Override
public Object unmarshal(HierarchicalStreamReader reader,
     UnmarshallingContext context)
{
  return ZonedDateTime.parse(reader.getValue(), DateTimeFormatter.ISO_OFFSET_DATE_TIME);
}
}

我注册转换器:

XStream xstream = new XStream();
xstream.registerConverter(new ZonedDateTimeConverter());

但我总是得到一个错误:

com.thoughtworks.xstream.converters.ConversionException: Cannot deserialize object with new readObject()/writeObject() methods

---- Debugging information ----
class               : java.time.ZonedDateTime
required-type       : java.time.ZonedDateTime
converter-type      : com.thoughtworks.xstream.converters.reflection.SerializableConverter
path                : /de.unigreifswald.floradb.importer.model.ImportJob/exportDate
line number         : 5
class[1]            : de.unigreifswald.floradb.importer.model.ImportJob
converter-type[1]   : com.thoughtworks.xstream.converters.reflection.ReflectionConverter
version             : 1.4.6
-------------------------------
    at com.thoughtworks.xstream.converters.reflection.SerializableConverter.doUnmarshal(SerializableConverter.java:331)
    at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:257)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72)
    at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66)
    at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:474)
    at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:406)
    at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:257)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72)
    at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:50)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.start(TreeUnmarshaller.java:134)
    at com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.unmarshal(AbstractTreeMarshallingStrategy.java:32)
    at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1157)
    at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1141)
    at com.thoughtworks.xstream.XStream.fromXML(XStream.java:1105)
    at com.thoughtworks.xstream.XStream.fromXML(XStream.java:1047)
    at de.unigreifswald.floradb.importer.persistence.ImportJobDaoBeanSerialization.read(ImportJobDaoBeanSerialization.java:74)
    at de.unigreifswald.floradb.importer.persistence.ImportJobDaoBeanSerialization.visitFile(ImportJobDaoBeanSerialization.java:92)
    at de.unigreifswald.floradb.importer.persistence.ImportJobDaoBeanSerialization.visitFile(ImportJobDaoBeanSerialization.java:1)
    at java.nio.file.Files.walkFileTree(Files.java:2670)
    at java.nio.file.Files.walkFileTree(Files.java:2742)
    at de.unigreifswald.floradb.importer.persistence.ImportJobDaoBeanSerialization.get(ImportJobDaoBeanSerialization.java:84)
    at de.unigreifswald.floradb.importer.persistence.TestImportJobDaoBeanSerilaization.testPersist(TestImportJobDaoBeanSerilaization.java:69)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access[=13=]0(ParentRunner.java:58)
    at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:539)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:761)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:461)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:207)

我该怎么做才能解决这个问题?

https://github.com/x-stream/xstream/issues/24 上,joehni 提到 xstream 的新版本可以处理 java.time,这是事实。我从 xtream 1.4.6 更新到 1.4.10,现在 ZonedDateTime 处理得很好。