// =================================================================================================
// Copyright 2011 Twitter, Inc.
// -------------------------------------------------------------------------------------------------
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this work except in compliance with the License.
// You may obtain a copy of the License in the LICENSE file, or at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =================================================================================================
package com.twitter.common.base;
import com.google.common.base.Function;
/**
* A utility for transporting checked exceptions across boundaries that do not allow for checked
* exception propagation.
*
* @param <E> The type of checked exception the ExceptionTransported can transport
*
* @author John Sirois
*/
public class ExceptionTransporter<E extends Exception> {
/**
* An exception wrapper used to transport checked exceptions. Never leaves an
* {@link ExceptionTransporter#guard(com.google.common.base.Function)} call.
*/
private static final class TransportingException extends RuntimeException {
private TransportingException(Exception cause) {
super("It is a usage error to see this message!", cause);
}
}
/**
* Guards a unit of work that internally can generate checked exceptions. Callers wrap up the
* work in a function that rethrows any checked exceptions using the supplied
* ExceptionTransporter. Guard will ensure the original exception is unwrapped an re-thrown.
*
* @param work The unit of work that guards its checked exceptions.
* @param <T> The type returned by the unit of work when it successfully completes.
* @param <X> The type of checked exception that the unit of work wishes to guard.
* @return the result of the unit of work if no excpetions are thrown
* @throws X when the unit of work uses the ExceptionTransporter to throw a checked exception
*/
public static <T, X extends Exception> T guard(Function<ExceptionTransporter<X>, T> work)
throws X {
try {
return work.apply(new ExceptionTransporter<X>());
} catch (TransportingException e) {
@SuppressWarnings("unchecked")
X cause = (X) e.getCause();
throw cause;
}
}
/**
* Throws the given {@code checked} exception across a boundary that does not allow checked
* exceptions. Although a RuntimeException is returned by this method signature, the method never
* actually completes normally. The return type does allow the following usage idiom however:
* <pre>
* public String apply(ExceptionTransporter transporter) {
* try {
* return doChecked();
* } catch (CheckedException e) {
* // Although transport internally throws and does not return, we satisfy the compiler that
* // our method returns a value or throws by pretending to throw the RuntimeException that
* // never actually gets returned by transporter.transport(...)
* throw transporter.transport(e);
* }
* }
* </pre>
*
* @param checked The checked exception to transport.
* @return A RuntimeException that can be thrown to satisfy the compiler at the call site
*/
public RuntimeException transport(E checked) {
throw new TransportingException(checked);
}
}