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
相关产品推荐
相关产品推荐

