使用XStream 1.4.9序列化Throwable变量时抛出UnsupportedOperationException
XStream 1.4.9序列化异常时抛出UnsupportedOperationException(引入js-scriptengine后)
问题原因
引入js-scriptengine依赖后,脚本引擎执行错误抛出的IllegalArgumentException实际是com.oracle.truffle.api.exception.AbstractTruffleException的子类。XStream 1.4.9内置的ThrowableConverter在序列化Throwable对象时,会调用initCause(null)重置异常的关联原因,但Truffle框架的AbstractTruffleException重写了initCause方法,强制要求异常原因必须通过构造函数传入,不允许后续调用initCause修改,因此直接触发UnsupportedOperationException。
解决方案
1. 升级XStream到兼容版本
XStream在1.4.10及后续版本中修复了该问题——会提前通过反射判断initCause方法是否会抛出异常,避免触发不支持的操作。直接升级依赖即可:
<!-- Maven依赖示例 --> <dependency> <groupId>com.thoughtworks.xstream</groupId> <artifactId>xstream</artifactId> <version>1.4.20</version> <!-- 或更高稳定版本 --> </dependency>
2. 自定义Throwable转换器(无法升级XStream时)
重写XStream的Throwable转换器,跳过initCause的调用逻辑,直接序列化异常核心属性:
public class SafeThrowableConverter extends ThrowableConverter { public SafeThrowableConverter(Mapper mapper) { super(mapper); } @Override public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { Throwable throwable = (Throwable) source; // 序列化异常消息 writer.startNode("message"); writer.setValue(throwable.getMessage() == null ? "" : throwable.getMessage()); writer.endNode(); // 序列化堆栈轨迹 writer.startNode("stackTrace"); for (StackTraceElement element : throwable.getStackTrace()) { context.convertAnother(element); } writer.endNode(); // 序列化异常原因(避免触发initCause) Throwable cause = throwable.getCause(); if (cause != null && cause != throwable) { writer.startNode("cause"); context.convertAnother(cause); writer.endNode(); } } }
注册自定义转换器并使用:
XStream xstream = new XStream(); // 设置高优先级覆盖默认转换器 xstream.registerConverter(new SafeThrowableConverter(xstream.getMapper()), XStream.PRIORITY_VERY_HIGH); System.err.println(xstream.toXML(e));
3. 包装异常后序列化
将捕获到的Truffle异常包装为普通Java异常,再执行序列化:
try { final ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName("JavaScript"); Objects.toString(scriptEngine.eval("X"), null); } catch (Exception e) { // 用普通RuntimeException包装原异常 Exception wrapped = new RuntimeException(e.getMessage(), e); XStream xstream = new XStream(); System.err.println(xstream.toXML(wrapped)); }
内容的提问来源于stack exchange,提问作者a stand-out flamingo
相关产品推荐
相关产品推荐

