S-JIS[2026-06-13]

gRPC Java Status

Java版gRPCのStatusのメモ。


概要

gRPCでは、gRPCサーバーで発生したエラーをgRPCクライアントに伝えるのに、Statusを使う。

Statusのエラーコードは規定されている。

JavaではStatusExceptionあるいはStatusRuntimeExceptionでStatusを扱う。
これらの例外にはMetadata(trailers)を指定することが出来る。
Metadataではユーザー独自のメッセージを扱うことが出来る。


protoの例

独自メッセージを扱う例として、protobufで独自のmessageを定義する。

src/main/proto/error.proto:

syntax = "proto3";

package example.grpc;

option java_multiple_files = true;
option java_package = "com.example.grpc.proto";

message MyErrorInfo {
    int64 error_code = 1;
    string error_message = 2;
}

Java版gRPCサーバーの例

src/main/java/com/example/grpc/server/service/ExampleServiceImpl.java

    @Override
    public void sendInt64Pair(Int64PairRequest request, StreamObserver<Int64PairResponse> responseObserver) {
        〜
        {
            StatusException e = createStatusException();
            responseObserver.onError(e);
            return;
        }
        〜
    }

gRPCサーバーでresponseObserverのonError()を呼ぶと、gRPCクライアントにエラーが通知される。


import com.example.grpc.proto.MyErrorInfo;
import com.google.protobuf.Any;

import io.grpc.Status;
import io.grpc.StatusException;
import io.grpc.protobuf.StatusProto;
    public static StatusException createStatusException() {
        var builder = com.google.rpc.Status.newBuilder();

        var status = Status.INTERNAL;
        builder.setCode(status.getCode().value());

        builder.setMessage("my status message");

        var errorInfo = MyErrorInfo.newBuilder()
            .setErrorCode(789)
            .setErrorMessage("example error")
            .build();
        builder.addDetails(Any.pack(errorInfo));

        var statusProto = builder.build();
        return StatusProto.toStatusException(statusProto);
    }

通常使うio.grpc.Statusの他に、com.google.rpc.Statusという(パッケージ違いの)クラスがあるので注意。
Metadataを扱う際は、com.google.rpcの方を使う。

同様に、StatusProtoクラスもio.grpc.protobuf.StatusProtoとcom.google.rpc.StatusProtoがあるので注意。
ここで使うのはio.grpc.protobufの方。


Java版gRPCクライアントの例

src/main/java/com/example/grpc/client/service/ExampleServiceClient.java

        try {
            return blockingStub.sendInt64Pair(request);
        } catch (StatusRuntimeException e) {
            handleStatusException(e);
            return null;
        }

import com.example.grpc.proto.MyErrorInfo;
import com.google.protobuf.Any;
import com.google.protobuf.InvalidProtocolBufferException;

import io.grpc.Status;
import io.grpc.StatusRuntimeException;
import io.grpc.protobuf.StatusProto;
    public static void handleStatusException(StatusRuntimeException e) {
        {
            Status status = e.getStatus();
            String message = e.getMessage();
            System.out.printf("StatusRuntimeException: %s, %s%n", status, message);
        }

        com.google.rpc.Status protoStatus = StatusProto.fromThrowable(e);
        Status status = Status.fromCodeValue(protoStatus.getCode());
        String message = protoStatus.getMessage();
        System.out.printf("protoStatus: %s, %s%n", status, message);

        for (Any detail : protoStatus.getDetailsList()) {
            if (detail.is(MyErrorInfo.class)) {
                try {
                    var errorInfo = detail.unpack(MyErrorInfo.class);
                    System.out.printf("MyErrorInfo: %d, %s%n", errorInfo.getErrorCode(), errorInfo.getErrorMessage());
                } catch (InvalidProtocolBufferException e1) {
                    e1.printStackTrace();
                }
            }
        }
    }

実行結果の例

StatusRuntimeException: Status{code=INTERNAL, description=my status message, cause=null}, INTERNAL: my status message
protoStatus: Status{code=INTERNAL, description=null, cause=null}, my status message
MyErrorInfo: 789, example error

StatusRuntimeExceptionから直接getMessage()で取得したメッセージと、StatusProto経由で取得したメッセージは、Statusコードの部分が異なる。


gRPC Javaへ戻る / gRPCへ戻る / 技術メモへ戻る
メールの送信先:ひしだま