aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorCarl Mastrangelo <notcarl@google.com>2018-08-17 11:40:11 -0700
committerGitHub <noreply@github.com>2018-08-17 11:40:11 -0700
commit7fe49f9b520f3106cc147aaab644fff7b79df4b3 (patch)
tree7eb7d172ee16654ceda8f4ee153ae817158f7e8f /core
parent30a4bfb2f0d1daf38d3b59e633f300b8edba9faf (diff)
downloadgrpc-grpc-java-7fe49f9b520f3106cc147aaab644fff7b79df4b3.tar.gz
core: add ability to create stackless status exceptions
Diffstat (limited to 'core')
-rw-r--r--core/src/main/java/io/grpc/StatusException.java17
-rw-r--r--core/src/main/java/io/grpc/StatusRuntimeException.java18
-rw-r--r--core/src/test/java/io/grpc/StatusExceptionTest.java67
-rw-r--r--core/src/test/java/io/grpc/StatusRuntimeExceptionTest.java68
4 files changed, 170 insertions, 0 deletions
diff --git a/core/src/main/java/io/grpc/StatusException.java b/core/src/main/java/io/grpc/StatusException.java
index f9416bf72..e89ac16dc 100644
--- a/core/src/main/java/io/grpc/StatusException.java
+++ b/core/src/main/java/io/grpc/StatusException.java
@@ -27,6 +27,7 @@ public class StatusException extends Exception {
private static final long serialVersionUID = -660954903976144640L;
private final Status status;
private final Metadata trailers;
+ private final boolean fillInStackTrace;
/**
* Constructs an exception with both a status. See also {@link Status#asException()}.
@@ -44,9 +45,25 @@ public class StatusException extends Exception {
* @since 1.0.0
*/
public StatusException(Status status, @Nullable Metadata trailers) {
+ this(status, trailers, /*fillInStackTrace=*/ true);
+ }
+
+ StatusException(Status status, @Nullable Metadata trailers, boolean fillInStackTrace) {
super(Status.formatThrowableMessage(status), status.getCause());
this.status = status;
this.trailers = trailers;
+ this.fillInStackTrace = fillInStackTrace;
+ fillInStackTrace();
+ }
+
+ @Override
+ public synchronized Throwable fillInStackTrace() {
+ // Let's observe final variables in two states! This works because Throwable will invoke this
+ // method before fillInStackTrace is set, thus doing nothing. After the constructor has set
+ // fillInStackTrace, this method will properly fill it in. Additionally, sub classes may call
+ // this normally, because fillInStackTrace will either be set, or this method will be
+ // overriden.
+ return fillInStackTrace ? super.fillInStackTrace() : this;
}
/**
diff --git a/core/src/main/java/io/grpc/StatusRuntimeException.java b/core/src/main/java/io/grpc/StatusRuntimeException.java
index d685464d4..27e2e6117 100644
--- a/core/src/main/java/io/grpc/StatusRuntimeException.java
+++ b/core/src/main/java/io/grpc/StatusRuntimeException.java
@@ -29,6 +29,8 @@ public class StatusRuntimeException extends RuntimeException {
private final Status status;
private final Metadata trailers;
+ private final boolean fillInStackTrace;
+
/**
* Constructs the exception with both a status. See also {@link Status#asException()}.
*
@@ -45,9 +47,25 @@ public class StatusRuntimeException extends RuntimeException {
* @since 1.0.0
*/
public StatusRuntimeException(Status status, @Nullable Metadata trailers) {
+ this(status, trailers, /*fillInStackTrace=*/ true);
+ }
+
+ StatusRuntimeException(Status status, @Nullable Metadata trailers, boolean fillInStackTrace) {
super(Status.formatThrowableMessage(status), status.getCause());
this.status = status;
this.trailers = trailers;
+ this.fillInStackTrace = fillInStackTrace;
+ fillInStackTrace();
+ }
+
+ @Override
+ public synchronized Throwable fillInStackTrace() {
+ // Let's observe final variables in two states! This works because Throwable will invoke this
+ // method before fillInStackTrace is set, thus doing nothing. After the constructor has set
+ // fillInStackTrace, this method will properly fill it in. Additionally, sub classes may call
+ // this normally, because fillInStackTrace will either be set, or this method will be
+ // overriden.
+ return fillInStackTrace ? super.fillInStackTrace() : this;
}
/**
diff --git a/core/src/test/java/io/grpc/StatusExceptionTest.java b/core/src/test/java/io/grpc/StatusExceptionTest.java
new file mode 100644
index 000000000..dd0d12dcc
--- /dev/null
+++ b/core/src/test/java/io/grpc/StatusExceptionTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2018 The gRPC 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 io.grpc;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Tests for {@link StatusException}.
+ */
+@RunWith(JUnit4.class)
+public class StatusExceptionTest {
+
+ @Test
+ public void internalCtorRemovesStack() {
+ StackTraceElement[] trace =
+ new StatusException(Status.CANCELLED, null, false) {}.getStackTrace();
+
+ assertThat(trace).isEmpty();
+ }
+
+ @Test
+ public void normalCtorKeepsStack() {
+ StackTraceElement[] trace =
+ new StatusException(Status.CANCELLED, null) {}.getStackTrace();
+
+ assertThat(trace).isNotEmpty();
+ }
+
+ @Test
+ public void extendPreservesStack() {
+ StackTraceElement[] trace = new StatusException(Status.CANCELLED) {}.getStackTrace();
+
+ assertThat(trace).isNotEmpty();
+ }
+
+ @Test
+ public void extendAndOverridePreservesStack() {
+ final StackTraceElement element = new StackTraceElement("a", "b", "c", 4);
+ StatusException exception = new StatusException(Status.CANCELLED, new Metadata()) {
+
+ @Override
+ public synchronized Throwable fillInStackTrace() {
+ setStackTrace(new StackTraceElement[]{element});
+ return this;
+ }
+ };
+ assertThat(exception.getStackTrace()).asList().containsExactly(element);
+ }
+}
diff --git a/core/src/test/java/io/grpc/StatusRuntimeExceptionTest.java b/core/src/test/java/io/grpc/StatusRuntimeExceptionTest.java
new file mode 100644
index 000000000..2c3bf7e9c
--- /dev/null
+++ b/core/src/test/java/io/grpc/StatusRuntimeExceptionTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2018 The gRPC 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 io.grpc;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Tests for {@link StatusRuntimeException}.
+ */
+@RunWith(JUnit4.class)
+public class StatusRuntimeExceptionTest {
+
+ @Test
+ public void internalCtorRemovesStack() {
+ StackTraceElement[] trace =
+ new StatusRuntimeException(Status.CANCELLED, null, false) {}.getStackTrace();
+
+ assertThat(trace).isEmpty();
+ }
+
+ @Test
+ public void normalCtorKeepsStack() {
+ StackTraceElement[] trace =
+ new StatusRuntimeException(Status.CANCELLED, null) {}.getStackTrace();
+
+ assertThat(trace).isNotEmpty();
+ }
+
+ @Test
+ public void extendPreservesStack() {
+ StackTraceElement[] trace = new StatusRuntimeException(Status.CANCELLED) {}.getStackTrace();
+
+ assertThat(trace).isNotEmpty();
+ }
+
+ @Test
+ public void extendAndOverridePreservesStack() {
+ final StackTraceElement element = new StackTraceElement("a", "b", "c", 4);
+ StatusRuntimeException exception =
+ new StatusRuntimeException(Status.CANCELLED, new Metadata()) {
+
+ @Override
+ public synchronized Throwable fillInStackTrace() {
+ setStackTrace(new StackTraceElement[]{element});
+ return this;
+ }
+ };
+ assertThat(exception.getStackTrace()).asList().containsExactly(element);
+ }
+}