I'm refactoring some code to use guava Cache.
Initial code:
public Post getPost(Integer key) throws SQLException, IOException {
return PostsDB.findPostByID(key);
}
In order not to break something I need to preserve any thrown exception as is, without wrapping it.
Current solution appears somewhat ugly:
public Post getPost(final Integer key) throws SQLException, IOException {
try {
return cache.get(key, new Callable<Post>() {
@Override
public Post call() throws Exception {
return PostsDB.findPostByID(key);
}
});
} catch (ExecutionException e) {
Throwable cause = e.getCause();
if (cause instanceof SQLException) {
throw (SQLException) cause;
} else if (cause instanceof IOException) {
throw (IOException) cause;
} else if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
} else if (cause instanceof Error) {
throw (Error) cause;
} else {
throw new IllegalStateException(e);
}
}
}
Is there any possible way to make it nicer?
Just after writing the question started thinking about utility method powered with generics. Then remembered something about Throwables. And yes, it's already there! )
It may also be necessary to handle UncheckedExecutionException or even ExecutionError.
So the solution is:
public Post getPost(final Integer key) throws SQLException, IOException {
try {
return cache.get(key, new Callable<Post>() {
@Override
public Post call() throws Exception {
return PostsDB.findPostByID(key);
}
});
} catch (ExecutionException e) {
Throwables.propagateIfPossible(
e.getCause(), SQLException.class, IOException.class);
throw new IllegalStateException(e);
} catch (UncheckedExecutionException e) {
Throwables.throwIfUnchecked(e.getCause());
throw new IllegalStateException(e);
}
}
Very nice!
See also ThrowablesExplained, LoadingCache.getUnchecked and Why we deprecated Throwables.propagate.