From 0782e12ce7ceb35c74199a8c489785526c8b1f6e Mon Sep 17 00:00:00 2001 From: cpovirk Date: Fri, 27 Dec 2024 07:37:18 -0800 Subject: [PATCH] Standardize on `sneakyThrow` for "impossible" checked exceptions. This makes our code behave the same for sneaky checked exceptions that occur _when our implementations use reflection_ as for those that occur when our implementations use direct calls. This shouldn't matter for any of the code that I'm migrating to `sneakyThrow` in this CL, but there are other cases in which it could matter, and we're probably best off standardizing on one approach, just as we've done for _catching_ sneaky checked exceptions. Plus, pull each package's `sneakyThrow` out into its own top-level class for reuse. Also, sneak in a few other tiny cleanups: - We don't normally use `@GwtCompatible` in Truth, so remove it from `J2ktIncompatible`. - We can now use `Primitives.wrap` to produce a better error message for `isIntanceOf(primitiveType)`. RELNOTES=n/a PiperOrigin-RevId: 710060382 --- .../common/base/AbstractIteratorTest.java | 15 +------ .../com/google/common/base/SneakyThrows.java | 43 +++++++++++++++++++ .../common/collect/AbstractIteratorTest.java | 15 +------ .../util/concurrent/AbstractFutureTest.java | 12 +----- .../google/common/collect/SneakyThrows.java | 43 +++++++++++++++++++ .../com/google/common/collect/Streams.java | 12 +----- .../com/google/common/hash/SneakyThrows.java | 43 +++++++++++++++++++ .../common/util/concurrent/MoreExecutors.java | 8 ++-- .../common/util/concurrent/SneakyThrows.java | 43 +++++++++++++++++++ .../common/base/AbstractIteratorTest.java | 15 +------ .../com/google/common/base/SneakyThrows.java | 43 +++++++++++++++++++ .../common/collect/AbstractIteratorTest.java | 15 +------ .../util/concurrent/AbstractFutureTest.java | 12 +----- .../google/common/collect/SneakyThrows.java | 43 +++++++++++++++++++ .../com/google/common/collect/Streams.java | 12 +----- .../common/hash/ChecksumHashFunction.java | 8 ++-- guava/src/com/google/common/hash/Hashing.java | 8 ++-- .../com/google/common/hash/SneakyThrows.java | 43 +++++++++++++++++++ .../common/util/concurrent/MoreExecutors.java | 8 ++-- .../common/util/concurrent/SneakyThrows.java | 43 +++++++++++++++++++ 20 files changed, 368 insertions(+), 116 deletions(-) create mode 100644 android/guava-tests/test/com/google/common/base/SneakyThrows.java create mode 100644 android/guava/src/com/google/common/collect/SneakyThrows.java create mode 100644 android/guava/src/com/google/common/hash/SneakyThrows.java create mode 100644 android/guava/src/com/google/common/util/concurrent/SneakyThrows.java create mode 100644 guava-tests/test/com/google/common/base/SneakyThrows.java create mode 100644 guava/src/com/google/common/collect/SneakyThrows.java create mode 100644 guava/src/com/google/common/hash/SneakyThrows.java create mode 100644 guava/src/com/google/common/util/concurrent/SneakyThrows.java diff --git a/android/guava-tests/test/com/google/common/base/AbstractIteratorTest.java b/android/guava-tests/test/com/google/common/base/AbstractIteratorTest.java index 0b0293f58b72..cb7d4306dc8a 100644 --- a/android/guava-tests/test/com/google/common/base/AbstractIteratorTest.java +++ b/android/guava-tests/test/com/google/common/base/AbstractIteratorTest.java @@ -17,6 +17,7 @@ package com.google.common.base; import static com.google.common.base.ReflectionFreeAssertThrows.assertThrows; +import static com.google.common.base.SneakyThrows.sneakyThrow; import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.GwtIncompatible; @@ -91,8 +92,7 @@ public Integer computeNext() { throw new AssertionError("Should not have been called again"); } else { haveBeenCalled = true; - sneakyThrow(new SomeCheckedException()); - throw new AssertionError(); // unreachable + throw sneakyThrow(new SomeCheckedException()); } } }; @@ -181,15 +181,4 @@ protected Integer computeNext() { // Technically we should test other reentrant scenarios (4 combinations of // hasNext/next), but we'll cop out for now, knowing that // next() both start by invoking hasNext() anyway. - - /** Throws an undeclared checked exception. */ - private static void sneakyThrow(Throwable t) { - class SneakyThrower { - @SuppressWarnings("unchecked") // intentionally unsafe for test - void throwIt(Throwable t) throws T { - throw (T) t; - } - } - new SneakyThrower().throwIt(t); - } } diff --git a/android/guava-tests/test/com/google/common/base/SneakyThrows.java b/android/guava-tests/test/com/google/common/base/SneakyThrows.java new file mode 100644 index 000000000000..7ad0d1690e20 --- /dev/null +++ b/android/guava-tests/test/com/google/common/base/SneakyThrows.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2015 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.base; + +import com.google.common.annotations.GwtCompatible; +import com.google.errorprone.annotations.CanIgnoreReturnValue; + +/** Static utility method for throwing an undeclared checked exception. */ +@GwtCompatible +final class SneakyThrows { + /** + * Throws an undeclared checked exception. + * + * @return never; this method declares a return type of {@link Error} only so that callers can + * write {@code throw sneakyThrow(t);} to convince the compiler that the statement will always + * throw. + */ + @CanIgnoreReturnValue + static Error sneakyThrow(Throwable t) { + throw new SneakyThrows().throwIt(t); + } + + @SuppressWarnings("unchecked") // not really safe, but that's the point + private Error throwIt(Throwable t) throws T { + throw (T) t; + } + + private SneakyThrows() {} +} diff --git a/android/guava-tests/test/com/google/common/collect/AbstractIteratorTest.java b/android/guava-tests/test/com/google/common/collect/AbstractIteratorTest.java index 0120ba36b56e..8c706a62e346 100644 --- a/android/guava-tests/test/com/google/common/collect/AbstractIteratorTest.java +++ b/android/guava-tests/test/com/google/common/collect/AbstractIteratorTest.java @@ -17,6 +17,7 @@ package com.google.common.collect; import static com.google.common.collect.ReflectionFreeAssertThrows.assertThrows; +import static com.google.common.collect.SneakyThrows.sneakyThrow; import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.GwtIncompatible; @@ -175,8 +176,7 @@ public Integer computeNext() { throw new AssertionError("Should not have been called again"); } else { haveBeenCalled = true; - sneakyThrow(new SomeCheckedException()); - throw new AssertionError(); // unreachable + throw sneakyThrow(new SomeCheckedException()); } } }; @@ -250,15 +250,4 @@ protected Integer computeNext() { // Technically we should test other reentrant scenarios (9 combinations of // hasNext/next/peek), but we'll cop out for now, knowing that peek() and // next() both start by invoking hasNext() anyway. - - /** Throws an undeclared checked exception. */ - private static void sneakyThrow(Throwable t) { - class SneakyThrower { - @SuppressWarnings("unchecked") // not really safe, but that's the point - void throwIt(Throwable t) throws T { - throw (T) t; - } - } - new SneakyThrower().throwIt(t); - } } diff --git a/android/guava-tests/test/com/google/common/util/concurrent/AbstractFutureTest.java b/android/guava-tests/test/com/google/common/util/concurrent/AbstractFutureTest.java index aa73f4df2e5e..218025105088 100644 --- a/android/guava-tests/test/com/google/common/util/concurrent/AbstractFutureTest.java +++ b/android/guava-tests/test/com/google/common/util/concurrent/AbstractFutureTest.java @@ -24,6 +24,7 @@ import static com.google.common.util.concurrent.Futures.immediateFailedFuture; import static com.google.common.util.concurrent.Futures.immediateFuture; import static com.google.common.util.concurrent.MoreExecutors.directExecutor; +import static com.google.common.util.concurrent.SneakyThrows.sneakyThrow; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.NANOSECONDS; import static java.util.concurrent.TimeUnit.SECONDS; @@ -1070,17 +1071,6 @@ public void testCatchesUndeclaredThrowableFromListener() { private static final class SomeCheckedException extends Exception {} - /** Throws an undeclared checked exception. */ - private static void sneakyThrow(Throwable t) { - class SneakyThrower { - @SuppressWarnings("unchecked") // intentionally unsafe for test - void throwIt(Throwable t) throws T { - throw (T) t; - } - } - new SneakyThrower().throwIt(t); - } - public void testTrustedGetFailure_completed() { SettableFuture future = SettableFuture.create(); future.set("261"); diff --git a/android/guava/src/com/google/common/collect/SneakyThrows.java b/android/guava/src/com/google/common/collect/SneakyThrows.java new file mode 100644 index 000000000000..ed13f34f4dc4 --- /dev/null +++ b/android/guava/src/com/google/common/collect/SneakyThrows.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2015 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.collect; + +import com.google.common.annotations.GwtCompatible; +import com.google.errorprone.annotations.CanIgnoreReturnValue; + +/** Static utility method for throwing an undeclared checked exception. */ +@GwtCompatible +final class SneakyThrows { + /** + * Throws an undeclared checked exception. + * + * @return never; this method declares a return type of {@link Error} only so that callers can + * write {@code throw sneakyThrow(t);} to convince the compiler that the statement will always + * throw. + */ + @CanIgnoreReturnValue + static Error sneakyThrow(Throwable t) { + throw new SneakyThrows().throwIt(t); + } + + @SuppressWarnings("unchecked") // not really safe, but that's the point + private Error throwIt(Throwable t) throws T { + throw (T) t; + } + + private SneakyThrows() {} +} diff --git a/android/guava/src/com/google/common/collect/Streams.java b/android/guava/src/com/google/common/collect/Streams.java index 9c1d58133c65..3c242e94b9b1 100644 --- a/android/guava/src/com/google/common/collect/Streams.java +++ b/android/guava/src/com/google/common/collect/Streams.java @@ -18,6 +18,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.NullnessCasts.uncheckedCastNullableTToT; +import static com.google.common.collect.SneakyThrows.sneakyThrow; import static java.lang.Math.min; import static java.util.Objects.requireNonNull; @@ -179,17 +180,6 @@ private static void closeAll(BaseStream[] toClose) { } } - /** Throws an undeclared checked exception. */ - private static void sneakyThrow(Throwable t) { - class SneakyThrower { - @SuppressWarnings("unchecked") // not really safe, but that's the point - void throwIt(Throwable t) throws T { - throw (T) t; - } - } - new SneakyThrower().throwIt(t); - } - /** * Returns a {@link Stream} containing the elements of the first stream, followed by the elements * of the second stream, and so on. diff --git a/android/guava/src/com/google/common/hash/SneakyThrows.java b/android/guava/src/com/google/common/hash/SneakyThrows.java new file mode 100644 index 000000000000..918d144597ac --- /dev/null +++ b/android/guava/src/com/google/common/hash/SneakyThrows.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2015 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.hash; + +import com.google.common.annotations.GwtCompatible; +import com.google.errorprone.annotations.CanIgnoreReturnValue; + +/** Static utility method for throwing an undeclared checked exception. */ +@GwtCompatible +final class SneakyThrows { + /** + * Throws an undeclared checked exception. + * + * @return never; this method declares a return type of {@link Error} only so that callers can + * write {@code throw sneakyThrow(t);} to convince the compiler that the statement will always + * throw. + */ + @CanIgnoreReturnValue + static Error sneakyThrow(Throwable t) { + throw new SneakyThrows().throwIt(t); + } + + @SuppressWarnings("unchecked") // not really safe, but that's the point + private Error throwIt(Throwable t) throws T { + throw (T) t; + } + + private SneakyThrows() {} +} diff --git a/android/guava/src/com/google/common/util/concurrent/MoreExecutors.java b/android/guava/src/com/google/common/util/concurrent/MoreExecutors.java index 110a2458b909..1578a2539d56 100644 --- a/android/guava/src/com/google/common/util/concurrent/MoreExecutors.java +++ b/android/guava/src/com/google/common/util/concurrent/MoreExecutors.java @@ -16,8 +16,8 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Throwables.throwIfUnchecked; import static com.google.common.util.concurrent.Internal.toNanosSaturated; +import static com.google.common.util.concurrent.SneakyThrows.sneakyThrow; import static java.util.Objects.requireNonNull; import com.google.common.annotations.GwtCompatible; @@ -30,7 +30,6 @@ import com.google.common.util.concurrent.ForwardingListenableFuture.SimpleForwardingListenableFuture; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.UndeclaredThrowableException; import java.time.Duration; import java.util.Collection; import java.util.Iterator; @@ -816,9 +815,8 @@ public static ThreadFactory platformThreadFactory() { } catch (IllegalAccessException | ClassNotFoundException | NoSuchMethodException e) { throw new RuntimeException("Couldn't invoke ThreadManager.currentRequestThreadFactory", e); } catch (InvocationTargetException e) { - throwIfUnchecked(e.getCause()); - // This should be impossible: `currentRequestThreadFactory` has no `throws` clause. - throw new UndeclaredThrowableException(e.getCause()); + // `currentRequestThreadFactory` has no `throws` clause. + throw sneakyThrow(e.getCause()); } } diff --git a/android/guava/src/com/google/common/util/concurrent/SneakyThrows.java b/android/guava/src/com/google/common/util/concurrent/SneakyThrows.java new file mode 100644 index 000000000000..ca448c42c121 --- /dev/null +++ b/android/guava/src/com/google/common/util/concurrent/SneakyThrows.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2015 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.util.concurrent; + +import com.google.common.annotations.GwtCompatible; +import com.google.errorprone.annotations.CanIgnoreReturnValue; + +/** Static utility method for throwing an undeclared checked exception. */ +@GwtCompatible +final class SneakyThrows { + /** + * Throws an undeclared checked exception. + * + * @return never; this method declares a return type of {@link Error} only so that callers can + * write {@code throw sneakyThrow(t);} to convince the compiler that the statement will always + * throw. + */ + @CanIgnoreReturnValue + static Error sneakyThrow(Throwable t) { + throw new SneakyThrows().throwIt(t); + } + + @SuppressWarnings("unchecked") // not really safe, but that's the point + private Error throwIt(Throwable t) throws T { + throw (T) t; + } + + private SneakyThrows() {} +} diff --git a/guava-tests/test/com/google/common/base/AbstractIteratorTest.java b/guava-tests/test/com/google/common/base/AbstractIteratorTest.java index 0b0293f58b72..cb7d4306dc8a 100644 --- a/guava-tests/test/com/google/common/base/AbstractIteratorTest.java +++ b/guava-tests/test/com/google/common/base/AbstractIteratorTest.java @@ -17,6 +17,7 @@ package com.google.common.base; import static com.google.common.base.ReflectionFreeAssertThrows.assertThrows; +import static com.google.common.base.SneakyThrows.sneakyThrow; import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.GwtIncompatible; @@ -91,8 +92,7 @@ public Integer computeNext() { throw new AssertionError("Should not have been called again"); } else { haveBeenCalled = true; - sneakyThrow(new SomeCheckedException()); - throw new AssertionError(); // unreachable + throw sneakyThrow(new SomeCheckedException()); } } }; @@ -181,15 +181,4 @@ protected Integer computeNext() { // Technically we should test other reentrant scenarios (4 combinations of // hasNext/next), but we'll cop out for now, knowing that // next() both start by invoking hasNext() anyway. - - /** Throws an undeclared checked exception. */ - private static void sneakyThrow(Throwable t) { - class SneakyThrower { - @SuppressWarnings("unchecked") // intentionally unsafe for test - void throwIt(Throwable t) throws T { - throw (T) t; - } - } - new SneakyThrower().throwIt(t); - } } diff --git a/guava-tests/test/com/google/common/base/SneakyThrows.java b/guava-tests/test/com/google/common/base/SneakyThrows.java new file mode 100644 index 000000000000..7ad0d1690e20 --- /dev/null +++ b/guava-tests/test/com/google/common/base/SneakyThrows.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2015 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.base; + +import com.google.common.annotations.GwtCompatible; +import com.google.errorprone.annotations.CanIgnoreReturnValue; + +/** Static utility method for throwing an undeclared checked exception. */ +@GwtCompatible +final class SneakyThrows { + /** + * Throws an undeclared checked exception. + * + * @return never; this method declares a return type of {@link Error} only so that callers can + * write {@code throw sneakyThrow(t);} to convince the compiler that the statement will always + * throw. + */ + @CanIgnoreReturnValue + static Error sneakyThrow(Throwable t) { + throw new SneakyThrows().throwIt(t); + } + + @SuppressWarnings("unchecked") // not really safe, but that's the point + private Error throwIt(Throwable t) throws T { + throw (T) t; + } + + private SneakyThrows() {} +} diff --git a/guava-tests/test/com/google/common/collect/AbstractIteratorTest.java b/guava-tests/test/com/google/common/collect/AbstractIteratorTest.java index 0120ba36b56e..8c706a62e346 100644 --- a/guava-tests/test/com/google/common/collect/AbstractIteratorTest.java +++ b/guava-tests/test/com/google/common/collect/AbstractIteratorTest.java @@ -17,6 +17,7 @@ package com.google.common.collect; import static com.google.common.collect.ReflectionFreeAssertThrows.assertThrows; +import static com.google.common.collect.SneakyThrows.sneakyThrow; import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.GwtIncompatible; @@ -175,8 +176,7 @@ public Integer computeNext() { throw new AssertionError("Should not have been called again"); } else { haveBeenCalled = true; - sneakyThrow(new SomeCheckedException()); - throw new AssertionError(); // unreachable + throw sneakyThrow(new SomeCheckedException()); } } }; @@ -250,15 +250,4 @@ protected Integer computeNext() { // Technically we should test other reentrant scenarios (9 combinations of // hasNext/next/peek), but we'll cop out for now, knowing that peek() and // next() both start by invoking hasNext() anyway. - - /** Throws an undeclared checked exception. */ - private static void sneakyThrow(Throwable t) { - class SneakyThrower { - @SuppressWarnings("unchecked") // not really safe, but that's the point - void throwIt(Throwable t) throws T { - throw (T) t; - } - } - new SneakyThrower().throwIt(t); - } } diff --git a/guava-tests/test/com/google/common/util/concurrent/AbstractFutureTest.java b/guava-tests/test/com/google/common/util/concurrent/AbstractFutureTest.java index aa73f4df2e5e..218025105088 100644 --- a/guava-tests/test/com/google/common/util/concurrent/AbstractFutureTest.java +++ b/guava-tests/test/com/google/common/util/concurrent/AbstractFutureTest.java @@ -24,6 +24,7 @@ import static com.google.common.util.concurrent.Futures.immediateFailedFuture; import static com.google.common.util.concurrent.Futures.immediateFuture; import static com.google.common.util.concurrent.MoreExecutors.directExecutor; +import static com.google.common.util.concurrent.SneakyThrows.sneakyThrow; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.NANOSECONDS; import static java.util.concurrent.TimeUnit.SECONDS; @@ -1070,17 +1071,6 @@ public void testCatchesUndeclaredThrowableFromListener() { private static final class SomeCheckedException extends Exception {} - /** Throws an undeclared checked exception. */ - private static void sneakyThrow(Throwable t) { - class SneakyThrower { - @SuppressWarnings("unchecked") // intentionally unsafe for test - void throwIt(Throwable t) throws T { - throw (T) t; - } - } - new SneakyThrower().throwIt(t); - } - public void testTrustedGetFailure_completed() { SettableFuture future = SettableFuture.create(); future.set("261"); diff --git a/guava/src/com/google/common/collect/SneakyThrows.java b/guava/src/com/google/common/collect/SneakyThrows.java new file mode 100644 index 000000000000..ed13f34f4dc4 --- /dev/null +++ b/guava/src/com/google/common/collect/SneakyThrows.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2015 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.collect; + +import com.google.common.annotations.GwtCompatible; +import com.google.errorprone.annotations.CanIgnoreReturnValue; + +/** Static utility method for throwing an undeclared checked exception. */ +@GwtCompatible +final class SneakyThrows { + /** + * Throws an undeclared checked exception. + * + * @return never; this method declares a return type of {@link Error} only so that callers can + * write {@code throw sneakyThrow(t);} to convince the compiler that the statement will always + * throw. + */ + @CanIgnoreReturnValue + static Error sneakyThrow(Throwable t) { + throw new SneakyThrows().throwIt(t); + } + + @SuppressWarnings("unchecked") // not really safe, but that's the point + private Error throwIt(Throwable t) throws T { + throw (T) t; + } + + private SneakyThrows() {} +} diff --git a/guava/src/com/google/common/collect/Streams.java b/guava/src/com/google/common/collect/Streams.java index b59f0186c848..bb630caf569b 100644 --- a/guava/src/com/google/common/collect/Streams.java +++ b/guava/src/com/google/common/collect/Streams.java @@ -18,6 +18,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.NullnessCasts.uncheckedCastNullableTToT; +import static com.google.common.collect.SneakyThrows.sneakyThrow; import static java.lang.Math.min; import static java.util.Objects.requireNonNull; @@ -172,17 +173,6 @@ private static void closeAll(BaseStream[] toClose) { } } - /** Throws an undeclared checked exception. */ - private static void sneakyThrow(Throwable t) { - class SneakyThrower { - @SuppressWarnings("unchecked") // not really safe, but that's the point - void throwIt(Throwable t) throws T { - throw (T) t; - } - } - new SneakyThrower().throwIt(t); - } - /** * Returns a {@link Stream} containing the elements of the first stream, followed by the elements * of the second stream, and so on. diff --git a/guava/src/com/google/common/hash/ChecksumHashFunction.java b/guava/src/com/google/common/hash/ChecksumHashFunction.java index 7bca256737ef..ad613eba2158 100644 --- a/guava/src/com/google/common/hash/ChecksumHashFunction.java +++ b/guava/src/com/google/common/hash/ChecksumHashFunction.java @@ -16,7 +16,7 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Throwables.throwIfUnchecked; +import static com.google.common.hash.SneakyThrows.sneakyThrow; import com.google.errorprone.annotations.Immutable; import com.google.j2objc.annotations.J2ObjCIncompatible; @@ -24,7 +24,6 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import java.lang.reflect.UndeclaredThrowableException; import java.nio.ByteBuffer; import java.util.zip.Checksum; import org.jspecify.annotations.Nullable; @@ -116,9 +115,8 @@ static boolean updateByteBuffer(Checksum cs, ByteBuffer bb) { try { UPDATE_BB.invokeExact(cs, bb); } catch (Throwable e) { - throwIfUnchecked(e); - // This should be impossible, since `update` has no `throws` clause. - throw new UndeclaredThrowableException(e); + // `update` has no `throws` clause. + sneakyThrow(e); } return true; } else { diff --git a/guava/src/com/google/common/hash/Hashing.java b/guava/src/com/google/common/hash/Hashing.java index 7cb7fcd944ee..3f91ddcfcf7d 100644 --- a/guava/src/com/google/common/hash/Hashing.java +++ b/guava/src/com/google/common/hash/Hashing.java @@ -16,14 +16,13 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Throwables.throwIfUnchecked; +import static com.google.common.hash.SneakyThrows.sneakyThrow; import static java.lang.invoke.MethodType.methodType; import com.google.errorprone.annotations.Immutable; import com.google.j2objc.annotations.J2ObjCIncompatible; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; -import java.lang.reflect.UndeclaredThrowableException; import java.security.Key; import java.util.ArrayList; import java.util.Arrays; @@ -519,9 +518,8 @@ static Checksum newCrc32c() { try { return (Checksum) CONSTRUCTOR.invokeExact(); } catch (Throwable e) { - throwIfUnchecked(e); - // This should be impossible, since the constructor has no `throws` clause. - throw new UndeclaredThrowableException(e); + // The constructor has no `throws` clause. + throw sneakyThrow(e); } } diff --git a/guava/src/com/google/common/hash/SneakyThrows.java b/guava/src/com/google/common/hash/SneakyThrows.java new file mode 100644 index 000000000000..918d144597ac --- /dev/null +++ b/guava/src/com/google/common/hash/SneakyThrows.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2015 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.hash; + +import com.google.common.annotations.GwtCompatible; +import com.google.errorprone.annotations.CanIgnoreReturnValue; + +/** Static utility method for throwing an undeclared checked exception. */ +@GwtCompatible +final class SneakyThrows { + /** + * Throws an undeclared checked exception. + * + * @return never; this method declares a return type of {@link Error} only so that callers can + * write {@code throw sneakyThrow(t);} to convince the compiler that the statement will always + * throw. + */ + @CanIgnoreReturnValue + static Error sneakyThrow(Throwable t) { + throw new SneakyThrows().throwIt(t); + } + + @SuppressWarnings("unchecked") // not really safe, but that's the point + private Error throwIt(Throwable t) throws T { + throw (T) t; + } + + private SneakyThrows() {} +} diff --git a/guava/src/com/google/common/util/concurrent/MoreExecutors.java b/guava/src/com/google/common/util/concurrent/MoreExecutors.java index 596674333b6e..607f0c8f40fc 100644 --- a/guava/src/com/google/common/util/concurrent/MoreExecutors.java +++ b/guava/src/com/google/common/util/concurrent/MoreExecutors.java @@ -16,8 +16,8 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Throwables.throwIfUnchecked; import static com.google.common.util.concurrent.Internal.toNanosSaturated; +import static com.google.common.util.concurrent.SneakyThrows.sneakyThrow; import static java.util.Objects.requireNonNull; import com.google.common.annotations.GwtCompatible; @@ -30,7 +30,6 @@ import com.google.common.util.concurrent.ForwardingListenableFuture.SimpleForwardingListenableFuture; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.UndeclaredThrowableException; import java.time.Duration; import java.util.Collection; import java.util.Iterator; @@ -808,9 +807,8 @@ public static ThreadFactory platformThreadFactory() { } catch (IllegalAccessException | ClassNotFoundException | NoSuchMethodException e) { throw new RuntimeException("Couldn't invoke ThreadManager.currentRequestThreadFactory", e); } catch (InvocationTargetException e) { - throwIfUnchecked(e.getCause()); - // This should be impossible: `currentRequestThreadFactory` has no `throws` clause. - throw new UndeclaredThrowableException(e.getCause()); + // `currentRequestThreadFactory` has no `throws` clause. + throw sneakyThrow(e.getCause()); } } diff --git a/guava/src/com/google/common/util/concurrent/SneakyThrows.java b/guava/src/com/google/common/util/concurrent/SneakyThrows.java new file mode 100644 index 000000000000..ca448c42c121 --- /dev/null +++ b/guava/src/com/google/common/util/concurrent/SneakyThrows.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2015 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.util.concurrent; + +import com.google.common.annotations.GwtCompatible; +import com.google.errorprone.annotations.CanIgnoreReturnValue; + +/** Static utility method for throwing an undeclared checked exception. */ +@GwtCompatible +final class SneakyThrows { + /** + * Throws an undeclared checked exception. + * + * @return never; this method declares a return type of {@link Error} only so that callers can + * write {@code throw sneakyThrow(t);} to convince the compiler that the statement will always + * throw. + */ + @CanIgnoreReturnValue + static Error sneakyThrow(Throwable t) { + throw new SneakyThrows().throwIt(t); + } + + @SuppressWarnings("unchecked") // not really safe, but that's the point + private Error throwIt(Throwable t) throws T { + throw (T) t; + } + + private SneakyThrows() {} +}