Saxon 10 DateTime变量被识别为字符串及序列化异常求助
Saxon 10迁移中的两个问题解决方案
一、DateTime变量被识别为字符串的问题
问题现象
原有表达式current-dateTime() - $datetime报错,提示操作数类型不匹配(xs:dateTimestamp和xs:string),Saxon 10将$datetime识别为字符串类型,而Saxon 9中可直接按DateTime类型处理。
原因
Saxon 10.5开始将AtomicValue标记为非序列化,导致Java端传入的DateTimeValue对象在XPath上下文传递过程中无法保持原有类型,被降级为字符串。
解决方案
临时修复:强制类型转换
保留当前使用的强制转换方式,确保表达式正常执行:current-dateTime() - xs:dateTime($datetime)根本修复:正确注册变量类型
在Java代码向XPath上下文注入$datetime变量时,显式指定其类型为xs:dateTime,而非直接传递字符串或未类型化对象:// 示例:基于Saxon API的变量注册 XPathCompiler compiler = processor.newXPathCompiler(); // 声明变量并指定类型为xs:dateTime compiler.declareVariable(new QName("datetime"), ItemType.DATE_TIME); // 执行时传入DateTimeValue对象 XPathSelector selector = executable.load(); selector.setVariable(new QName("datetime"), dateTimeValue);此方式下Saxon会直接识别变量为
xs:dateTime类型,无需手动转换。
二、深拷贝时的序列化异常问题
问题现象
调用completeCopy方法执行深拷贝时抛出java.io.NotSerializableException,涉及XSDateTimeDummyProperty类和内部的DateTimeValue对象。
原因
XSDateTimeDummyProperty及其父类SaxonParentProperty未实现Serializable接口;- 即使实现
Serializable,Saxon 10.5后的AtomicValue(包括DateTimeValue)被标记为非序列化,内部obj字段无法被序列化。
解决方案
放弃基于序列化的深拷贝方式,改用基于对象内容的手动复制:
- 修改
completeCopy方法,通过DateTimeValue的字符串表示重新创建对象:public static <T extends XSDateTimeDummyProperty> T completeCopy(T orig) { if (orig == null) { return null; } try { // 创建实例副本 T copy = orig.getClass().getDeclaredConstructor().newInstance(); // 基于原有DateTimeValue的字符串值重新生成对象 if (orig.obj != null) { String dateTimeStr = orig.obj.getStringValue(); ConversionResult conversionResult = DateTimeValue.makeDateTimeValue(dateTimeStr, ConversionRules.DEFAULT); copy.obj = (DateTimeValue) conversionResult; } return copy; } catch (Exception e) { throw new RuntimeException(e); } } - 可选:保留序列化能力的适配
若需保留序列化功能,可将obj字段标记为transient,并实现readObject/writeObject方法手动处理DateTimeValue的序列化逻辑:public class XSDateTimeDummyProperty extends SaxonParentProperty<DateTimeValue> implements Serializable { private static final long serialVersionUID = 1L; transient DateTimeValue obj; private void writeObject(ObjectOutputStream out) throws IOException { out.defaultWriteObject(); // 写入DateTimeValue的字符串表示 out.writeObject(obj != null ? obj.getStringValue() : null); } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); // 读取字符串并重新转换为DateTimeValue String dateTimeStr = (String) in.readObject(); if (dateTimeStr != null) { ConversionResult conversionResult = DateTimeValue.makeDateTimeValue(dateTimeStr, ConversionRules.DEFAULT); this.obj = (DateTimeValue) conversionResult; } } // 原有方法... }
内容的提问来源于stack exchange,提问作者Siddhant K.
相关产品推荐
相关产品推荐

