傑克遜和那可怕的IOException

2022-09-03 02:04:53

Jackson 的成员抛出三个选中的异常:ObjectMapper#readValue

IOException 
JsonParseException 
JsonMappingException

JsonParseException并扩展 .我想包装前面提到的两个子类并抛出我自己的自定义异常,但是,基类,正在检查,要求我也捕获或丢弃它。JsonMappingExceptionIOExceptionIOException

对我来说,把东西扔到调用层是没有意义的,但是,不利的是,如果我把它藏起来,它就是一种气味。我最初的想法是不要捕获它,并将其留给调用方/运行时异常机制来处理它......但是,我不想强迫调用方捕获或指定。IOException

在这种情况下,人们会怎么做?


答案 1

简短的回答:如果你处理IO,你处理s。如果您不处理 IO,则 s 应转换为未经检查的异常,因为它们是错误代码的症状。IOExceptionIOException


更长的答案:

readValue总是采用 一个 ,它可以包裹在 IO 周围(例如,文件或 URL)。如果您正在处理IO,则无法处理,您应该处理它们或以某种方式重新删除/传递它们。在 IO 期间可能发生任何事情,您应该准备好处理异常。JsonParserIOException

但是,如果您确定您的实例不使用 IO(例如,您曾经在字符串上创建 JSON 解析器),则可以假设您收到的任何 都是 bug,无论是在代码中还是在 Jackson 中。通常,抛出一个未经检查的异常是处理它的正确方法:JsonParserJsonFactory#createJsonParser(java.lang.String)IOException

ObjectMapper om = new ObjectMapper(/* whatever */);
JsonParser jp = JsonFactory.createJsonParser("{ \"foo\": \"bar\" }");
try {
    return om.readValue(jp);
} catch (IOException e) {
    throw new AssertionError("An IOException occurred when this was assumed to be impossible.");
}

Nota bene:我的Java很生锈,我从来没有使用过Jackson,所以把上面的块看作是伪代码。

在任何情况下,您永远不需要在 中声明,因为它们是未经检查的异常。所有属于 或 不需要显式捕获或重写的子类。这些异常用于预期不会发生的问题,除非你正在处理有缺陷的代码或 VM 的主机着火了。AssertionErrorthrowsjava.lang.RuntimeExceptionjava.lang.Error


答案 2

虽然这在Jackson中没有明确记录,但IOExceptions的基本原理很简单:来自输入源(和输出目标)的IOException被按原样抛出 - 因为Jackson本身不能为这些做任何事情,所以它们被按原样抛出。IOExceptions的唯一附加来源是概念上属于低级(数据格式无关)I / O处理的内容,特别是对字符编码(如UTF-8)的解码。

由此可见,JsonParsingException似乎相对直观地用于与尝试解析无效内容相关的问题;和 JsonMappingException,用于数据绑定级别的问题。一个