mirror of https://github.com/grpc/grpc-java.git
core: add ability to create stackless status exceptions
This commit is contained in:
parent
30a4bfb2f0
commit
7fe49f9b52
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue