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

StAX XML校验中自定义异常被包装为SAXException无法捕获的问题

问题根源分析

你的问题核心在于异常类型的继承关系和ErrorHandler的方法约束:

  • 你的CustomXmlValidationException继承了RuntimeException,但ErrorHandler的error()方法声明必须抛出SAXException(或其子类)。
  • 当你在error()方法中抛出RuntimeException类型的自定义异常时,Validator的底层逻辑会自动把它包装成一个SAXException抛出,导致外层catch (CustomXmlValidationException e)完全捕获不到目标异常——实际拿到的是包裹了自定义异常的SAXException。
解决方案

我们只需要调整自定义异常的继承关系,让它符合ErrorHandler的方法约束,就能直接捕获到自定义异常并获取行号、元素信息。

1. 修改自定义异常类

让CustomXmlValidationException继承SAXException而不是RuntimeException,这样它就符合ErrorHandler方法的抛出声明:

import org.xml.sax.SAXException;

public class CustomXmlValidationException extends SAXException {
    private int lineNo;
    private String element;

    public CustomXmlValidationException(String message, int lineNo, String element) {
        super(message);
        this.lineNo = lineNo;
        this.element = element;
    }

    public int getLineNo() {
        return lineNo;
    }

    public String getElement() {
        return element;
    }
}

2. 完善CustomErrorHandler的错误处理

确保error()和fatalError()都抛出自定义异常(现在它是SAXException的子类,完全符合方法签名),避免严重错误被忽略:

public class CustomErrorHandler implements ErrorHandler {
    private boolean isValid = true;
    private XMLStreamReader reader;

    public CustomErrorHandler(XMLStreamReader reader) {
        this.reader = reader;
    }

    public boolean isValid() {
        return this.isValid;
    }

    @Override
    public void error(SAXParseException exc) throws SAXException {
        isValid = false;
        throw new CustomXmlValidationException(exc.getMessage(), exc.getLineNumber(), reader.getLocalName());
    }

    @Override
    public void fatalError(SAXParseException exc) throws SAXException {
        isValid = false;
        throw new CustomXmlValidationException(exc.getMessage(), exc.getLineNumber(), reader.getLocalName());
    }

    @Override
    public void warning(SAXParseException e) {
        // 可根据需求处理警告,比如打印日志
    }
}

3. 调整validateXml方法的捕获逻辑

现在自定义异常是SAXException的子类,需要把它的捕获块放在SAXException捕获块的前面(否则会被父类异常块拦截):

public static String validateXml(InputStream inputXml) throws XMLStreamException {
    try {
        SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        javax.xml.validation.Validator validator = factory.newSchema(getXSD()).newValidator();
        XMLStreamReader reader = XMLInputFactory.newFactory().createXMLStreamReader(inputXml);
        validator.setErrorHandler(new CustomErrorHandler(reader));
        validator.validate(new StAXSource(reader));
    } catch (CustomXmlValidationException e) {
        // 直接捕获自定义异常,拿到行号和元素信息
        return prepareValidationErrorMessageWithLineNo(e.getLineNo(), e.getMessage(), e.getElement());
    } catch (IOException | URISyntaxException | SAXException e) {
        // 处理其他非自定义的SAX异常或IO等异常
        return String.format("Validation error: %s", e.getMessage());
    }
    return null;
}

这样修改后,当XML校验出错时,你就能直接捕获到CustomXmlValidationException,顺利获取错误对应的行号和元素信息了。

内容的提问来源于stack exchange,提问作者tent0p11

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 10:37:53