You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 12:45:37