Skip to content

Commit

Permalink
Standardize on sneakyThrow for "impossible" checked exceptions.
Browse files Browse the repository at this point in the history
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: 710111747
  • Loading branch information
cpovirk authored and Google Java Core Libraries committed Dec 27, 2024
1 parent ed1ed3d commit 54b8c47
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

package com.google.common.truth;

import com.google.common.annotations.GwtCompatible;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
Expand All @@ -26,5 +25,4 @@
*/
@Retention(RetentionPolicy.CLASS)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD})
@GwtCompatible
@interface J2ktIncompatible {}
4 changes: 2 additions & 2 deletions core/src/main/java/com/google/common/truth/Platform.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import static com.google.common.base.Throwables.throwIfUnchecked;
import static com.google.common.truth.DiffUtils.generateUnifiedDiff;
import static com.google.common.truth.Fact.fact;
import static com.google.common.truth.SneakyThrows.sneakyThrow;

import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
Expand Down Expand Up @@ -254,9 +255,8 @@ static AssertionError makeComparisonFailure(
try {
return constructor.newInstance(messages, facts, expected, actual, cause);
} catch (InvocationTargetException e) {
throwIfUnchecked(e.getCause());
// That constructor has no `throws` clause.
throw newLinkageError(e);
throw sneakyThrow(e.getCause());
} catch (InstantiationException e) {
// The class is a concrete class.
throw newLinkageError(e);
Expand Down
41 changes: 41 additions & 0 deletions core/src/main/java/com/google/common/truth/SneakyThrows.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2015 Google, Inc.
*
* 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.truth;

import com.google.errorprone.annotations.CanIgnoreReturnValue;

/** Static utility method for throwing an undeclared checked exception. */
final class SneakyThrows<T extends Throwable> {
/**
* 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<Error>().throwIt(t);
}

@SuppressWarnings("unchecked") // not really safe, but that's the point
private Error throwIt(Throwable t) throws T {
throw (T) t;
}

private SneakyThrows() {}
}
10 changes: 4 additions & 6 deletions core/src/main/java/com/google/common/truth/Subject.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import com.google.common.primitives.Chars;
import com.google.common.primitives.Ints;
import com.google.common.primitives.Longs;
import com.google.common.primitives.Primitives;
import com.google.common.primitives.Shorts;
import com.google.common.truth.FailureMetadata.OldAndNewValuesAreSimilar;
import com.google.errorprone.annotations.DoNotCall;
Expand Down Expand Up @@ -349,12 +350,9 @@ public void isNotInstanceOf(Class<?> clazz) {
private static boolean isInstanceOfType(Object instance, Class<?> clazz) {
checkArgument(
!clazz.isPrimitive(),
"Cannot check instanceof for primitive type %s. Pass the wrapper class instead.",
clazz.getSimpleName());
/*
* TODO(cpovirk): Make the message include `Primitives.wrap(clazz).getSimpleName()` once that
* method is available in a public guava-gwt release that we depend on.
*/
"Cannot check instanceof for primitive type %s. Pass the wrapper class %s instead.",
clazz.getSimpleName(),
Primitives.wrap(clazz).getSimpleName());
return Platform.isInstanceOfType(instance, clazz);
}

Expand Down

0 comments on commit 54b8c47

Please sign in to comment.