开发者

Jackson and that dreaded IOException

Jackson's ObjectMapper#readValue member throws three checked exceptions:

IOException 
JsonParseException 
JsonMappingException

JsonParseException and JsonMappingException extend IOException. I want to wrap the two aforementioned child class开发者_如何转开发es and throw my own custom exceptions, yet, the base class, IOException, being checked, requires me to either catch or throw it also.

It doesn't make sense for me to throw the IOException up to the calling layer, but, adversely, it's a smell if I hide it. My original thought was to not catch it and leave it to the caller/run-time exception mechanism to deal with it... yet, I don't want to have to force the caller to catch or specify.

What does one do in such a situation?


Short answer: if you deal with IO, you deal with IOExceptions. If you don't deal with IO, then IOExceptions should be turned into unchecked exceptions, because they're symptoms of buggy code.


Longer answer:

readValue always takes a JsonParser, which may be wrapped around IO (e.g. a file or a URL). If you're dealing with IO, there's no way around dealing with IOExceptions, and you should either handle them or rethrow/pass them in some way. Anything can happen during IO, and you should be prepared to deal with the exceptions.

However, if you are sure that your JsonParser instances don't use IO (e.g. you used JsonFactory#createJsonParser(java.lang.String) to create a JSON parser on a string), you may assume that any IOExceptions you receive are bugs, either in your code or in Jackson. Usually, throwing an unchecked exception is then the proper way to deal with it:

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: my Java is rusty and I've never used Jackson, so consider the above block to be pseudocode.

In any case, you never need to declare AssertionError in throws, because they're unchecked exceptions. Everything that's a subclass of java.lang.RuntimeException or java.lang.Error doesn't need to be caught or rethrown explicitly. These exceptions are used for problems that are not expected to occur unless you're dealing with buggy code or when your VM's host is on fire.


While this is not clearly documented within Jackson, rationale for IOExceptions is simple: IOExceptions from input sources (and output targets) are thrown as is -- since Jackson itself can not do anything for these, they are thrown as is. The only additional source for IOExceptions are things that are conceptually part of low-level (data-format independent) I/O handling, specifically, decoding of characters encodings like UTF-8.

From this, it seems relatively intuitive that JsonParsingException is for problems related to trying to parse invalid content; and JsonMappingException for problems at data-binding level. a


You should handle the IOException the same way you handle the json exceptions and wrap it. As the documentation of Jackson is lacking so much, you don't really know why any of them are thrown anyway (except for "an unknown error").


May patience got dried while wrapping dozen on methods in try/catch/rethrow boilerplate code. And I found Lombok can handle it for me. Hope it helps https://projectlombok.org/features/SneakyThrows

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜