/* * Copyright (C) 2012 The Guava Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License 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.google.common.io; import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.annotations.Beta; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Throwables; import java.io.Closeable; import java.io.IOException; import java.lang.reflect.Method; import java.util.ArrayDeque; import java.util.Deque; import java.util.logging.Level; import javax.annotation.Nullable; /** * A {@link Closeable} that collects {@code Closeable} resources and closes them all when it is * {@linkplain #close closed}. This is intended to approximately emulate the behavior of Java 7's * * try-with-resources statement in JDK6-compatible code. Running on Java 7, code using this * should be approximately equivalent in behavior to the same code written with try-with-resources. * Running on Java 6, exceptions that cannot be thrown must be logged rather than being added to the * thrown exception as a suppressed exception. * *
This class is intended to be used in the following pattern: * *
{@code
* Closer closer = Closer.create();
* try {
* InputStream in = closer.register(openInputStream());
* OutputStream out = closer.register(openOutputStream());
* // do stuff
* } catch (Throwable e) {
* // ensure that any checked exception types other than IOException that could be thrown are
* // provided here, e.g. throw closer.rethrow(e, CheckedException.class);
* throw closer.rethrow(e);
* } finally {
* closer.close();
* }}
*
* Note that this try-catch-finally block is not equivalent to a try-catch-finally block using * try-with-resources. To get the equivalent of that, you must wrap the above code in another * try block in order to catch any exception that may be thrown (including from the call to * {@code close()}). * *
This pattern ensures the following: * *
An exception that is suppressed is not thrown. The method of suppression used depends on the * version of Java the code is running on: * *
This method always throws, and as such should be called as * {@code throw closer.rethrow(e);} to ensure the compiler knows that it will throw. * * @return this method does not return; it always throws * @throws IOException when the given throwable is an IOException */ public RuntimeException rethrow(Throwable e) throws IOException { checkNotNull(e); thrown = e; Throwables.propagateIfPossible(e, IOException.class); throw new RuntimeException(e); } /** * Stores the given throwable and rethrows it. It will be rethrown as is if it is an * {@code IOException}, {@code RuntimeException}, {@code Error} or a checked exception of the * given type. Otherwise, it will be rethrown wrapped in a {@code RuntimeException}. Note: * Be sure to declare all of the checked exception types your try block can throw when calling an * overload of this method so as to avoid losing the original exception type. * *
This method always throws, and as such should be called as
* {@code throw closer.rethrow(e, ...);} to ensure the compiler knows that it will throw.
*
* @return this method does not return; it always throws
* @throws IOException when the given throwable is an IOException
* @throws X when the given throwable is of the declared type X
*/
public This method always throws, and as such should be called as
* {@code throw closer.rethrow(e, ...);} to ensure the compiler knows that it will throw.
*
* @return this method does not return; it always throws
* @throws IOException when the given throwable is an IOException
* @throws X1 when the given throwable is of the declared type X1
* @throws X2 when the given throwable is of the declared type X2
*/
public