diff --git a/protobuf/src/main/java/io/grpc/protobuf/StatusProto.java b/protobuf/src/main/java/io/grpc/protobuf/StatusProto.java index 2648138b93b..988e1938af0 100644 --- a/protobuf/src/main/java/io/grpc/protobuf/StatusProto.java +++ b/protobuf/src/main/java/io/grpc/protobuf/StatusProto.java @@ -147,14 +147,16 @@ public static com.google.rpc.Status fromThrowable(Throwable t) { } /** - * Extracts the google.rpc.Status from trailers, and makes sure they match the gRPC - * {@code status}. + * Extracts the {@code google.rpc.Status} from trailers, and makes sure they match the gRPC + * {@code status}. If the trailers do not contain a {@code google.rpc.Status}, it uses + * {@code status} param to generate a {@code google.rpc.Status}. * - * @return the embedded google.rpc.Status or {@code null} if it is not present. + * @return the embedded google.rpc.Status * @since 1.11.0 */ - @Nullable - public static com.google.rpc.Status fromStatusAndTrailers(Status status, Metadata trailers) { + public static com.google.rpc.Status fromStatusAndTrailers( + Status status, @Nullable Metadata trailers) { + checkNotNull(status, "status"); if (trailers != null) { com.google.rpc.Status statusProto = trailers.get(STATUS_DETAILS_KEY); if (statusProto != null) { @@ -164,6 +166,12 @@ public static com.google.rpc.Status fromStatusAndTrailers(Status status, Metadat return statusProto; } } - return null; + // fall-back to status, this is useful if the error is local. e.g. Server is unavailable. + com.google.rpc.Status.Builder statusBuilder = com.google.rpc.Status.newBuilder() + .setCode(status.getCode().value()); + if (status.getDescription() != null) { + statusBuilder.setMessage(status.getDescription()); + } + return statusBuilder.build(); } } diff --git a/protobuf/src/test/java/io/grpc/protobuf/StatusProtoTest.java b/protobuf/src/test/java/io/grpc/protobuf/StatusProtoTest.java index f981236523a..cf9c2c564ab 100644 --- a/protobuf/src/test/java/io/grpc/protobuf/StatusProtoTest.java +++ b/protobuf/src/test/java/io/grpc/protobuf/StatusProtoTest.java @@ -126,20 +126,25 @@ public void toStatusException_shouldThrowIfStatusCodeInvalid() throws Exception } @Test - public void fromThrowable_shouldReturnNullIfTrailersAreNull() { - Status status = Status.fromCodeValue(0); + public void fromThrowable_runtimeException_shouldReturnDerivedStatusIfTrailersAreNull() { + Status status = Status.UNAVAILABLE.withDescription("not available"); - assertNull(StatusProto.fromThrowable(status.asRuntimeException())); - assertNull(StatusProto.fromThrowable(status.asException())); + com.google.rpc.Status statusFromThrowable = + StatusProto.fromThrowable(status.asRuntimeException()); + + assertEquals(statusFromThrowable.getCode(), status.getCode().value()); + assertEquals(statusFromThrowable.getMessage(), status.getDescription()); } @Test - public void fromThrowable_shouldReturnNullIfStatusDetailsKeyIsMissing() { - Status status = Status.fromCodeValue(0); - Metadata emptyMetadata = new Metadata(); + public void fromThrowable_exception_shouldReturnDerivedStatusIfTrailersAreNull() { + Status status = Status.UNAVAILABLE.withDescription("not available"); + + com.google.rpc.Status statusFromThrowable = + StatusProto.fromThrowable(status.asException()); - assertNull(StatusProto.fromThrowable(status.asRuntimeException(emptyMetadata))); - assertNull(StatusProto.fromThrowable(status.asException(emptyMetadata))); + assertEquals(statusFromThrowable.getCode(), status.getCode().value()); + assertEquals(statusFromThrowable.getMessage(), status.getDescription()); } @Test