Skip to content

Commit

Permalink
api: StatusRuntimeException without stacktrace - Android compatibility (
Browse files Browse the repository at this point in the history
#11072)

This is an alternative to e36f099 that avoids the "fillInStaceTrace"
constructor which is only available starting at Android API level 24.
  • Loading branch information
panchenko authored Dec 22, 2024
1 parent 6516c73 commit ebe2b48
Show file tree
Hide file tree
Showing 9 changed files with 56 additions and 38 deletions.
12 changes: 5 additions & 7 deletions api/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,11 @@ dependencies {
extension = "signature"
}
}
// TODO: Temporarily disabled until StatusException is fixed.
// Context: https://github.com/grpc/grpc-java/pull/11066
//signature (libraries.signature.android) {
// artifact {
// extension = "signature"
// }
//}
signature (libraries.signature.android) {
artifact {
extension = "signature"
}
}
}

tasks.named("javadoc").configure {
Expand Down
9 changes: 4 additions & 5 deletions api/src/main/java/io/grpc/InternalStatus.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,11 @@ private InternalStatus() {}
public static final Metadata.Key<Status> CODE_KEY = Status.CODE_KEY;

/**
* Create a new {@link StatusRuntimeException} with the internal option of skipping the filling
* of the stack trace.
* Create a new {@link StatusRuntimeException} skipping the filling of the stack trace.
*/
@Internal
public static final StatusRuntimeException asRuntimeException(Status status,
@Nullable Metadata trailers, boolean fillInStackTrace) {
return new StatusRuntimeException(status, trailers, fillInStackTrace);
public static StatusRuntimeException asRuntimeExceptionWithoutStacktrace(Status status,
@Nullable Metadata trailers) {
return new InternalStatusRuntimeException(status, trailers);
}
}
39 changes: 39 additions & 0 deletions api/src/main/java/io/grpc/InternalStatusRuntimeException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright 2015 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 javax.annotation.Nullable;

/**
* StatusRuntimeException without stack trace, implemented as a subclass, as the
* {@code String, Throwable, boolean, boolean} constructor is not available in the supported
* version of Android.
*
* @see StatusRuntimeException
*/
class InternalStatusRuntimeException extends StatusRuntimeException {
private static final long serialVersionUID = 0;

public InternalStatusRuntimeException(Status status, @Nullable Metadata trailers) {
super(status, trailers);
}

@Override
public synchronized Throwable fillInStackTrace() {
return this;
}
}
7 changes: 1 addition & 6 deletions api/src/main/java/io/grpc/StatusException.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,7 @@ public StatusException(Status status) {
* @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(),
/* enableSuppression */ true, /* writableStackTrace */fillInStackTrace);
super(Status.formatThrowableMessage(status), status.getCause());
this.status = status;
this.trailers = trailers;
}
Expand Down
7 changes: 1 addition & 6 deletions api/src/main/java/io/grpc/StatusRuntimeException.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,7 @@ public StatusRuntimeException(Status status) {
* @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(),
/* enable suppressions */ true, /* writableStackTrace */ fillInStackTrace);
super(Status.formatThrowableMessage(status), status.getCause());
this.status = status;
this.trailers = trailers;
}
Expand Down
8 changes: 0 additions & 8 deletions api/src/test/java/io/grpc/StatusExceptionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,6 @@
@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 =
Expand Down
2 changes: 1 addition & 1 deletion api/src/test/java/io/grpc/StatusRuntimeExceptionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public class StatusRuntimeExceptionTest {
@Test
public void internalCtorRemovesStack() {
StackTraceElement[] trace =
new StatusRuntimeException(Status.CANCELLED, null, false) {}.getStackTrace();
new InternalStatusRuntimeException(Status.CANCELLED, null) {}.getStackTrace();

assertThat(trace).isEmpty();
}
Expand Down
6 changes: 3 additions & 3 deletions core/src/main/java/io/grpc/internal/ServerCallImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -373,10 +373,10 @@ private void closedInternal(Status status) {
} else {
call.cancelled = true;
listener.onCancel();
// The status will not have a cause in all failure scenarios but we want to make sure
// The status will not have a cause in all failure scenarios, but we want to make sure
// we always cancel the context with one to keep the context cancelled state consistent.
cancelCause = InternalStatus.asRuntimeException(
Status.CANCELLED.withDescription("RPC cancelled"), null, false);
cancelCause = InternalStatus.asRuntimeExceptionWithoutStacktrace(
Status.CANCELLED.withDescription("RPC cancelled"), null);
}
} finally {
// Cancel context after delivering RPC closure notification to allow the application to
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/java/io/grpc/internal/ServerImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -887,8 +887,8 @@ private void closedInternal(final Status status) {
// failed status has an exception we will create one here if needed.
Throwable cancelCause = status.getCause();
if (cancelCause == null) {
cancelCause = InternalStatus.asRuntimeException(
Status.CANCELLED.withDescription("RPC cancelled"), null, false);
cancelCause = InternalStatus.asRuntimeExceptionWithoutStacktrace(
Status.CANCELLED.withDescription("RPC cancelled"), null);
}

// The callExecutor might be busy doing user work. To avoid waiting, use an executor that
Expand Down

0 comments on commit ebe2b48

Please sign in to comment.