0

Parcelable data from client to server can use ParcelableUtils.metadataKey to build grpc [Metadata headers].

but, how to send Parcelable data from server to client??

[Metadata headers] is only client to server?

Seven Sir
  • 3
  • 2

1 Answers1

0

Metadata is available just before the request (i.e., headers), or just before or after the response (i.e., headers or trailers).

The basic approach is the same in all the cases: use an interceptor. But how you use an interceptor and communicate with the interceptor varies between client and server.

The header example shows a server interceptor adding metadata to response headers:

  @Override
  public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
      ServerCall<ReqT, RespT> call,
      final Metadata requestHeaders,
      ServerCallHandler<ReqT, RespT> next) {
    return next.startCall(new SimpleForwardingServerCall<ReqT, RespT>(call) {
      @Override
      public void sendHeaders(Metadata responseHeaders) {
        responseHeaders.put(CUSTOM_HEADER_KEY, "customRespondValue");
        super.sendHeaders(responseHeaders);
      }
    }, requestHeaders);
  }

That approach is the same independent of the type of Metadata (text, binary, or Parcelable). The only difference for the different types of Metadata is the construction of the Metadata.Key.

But with Binder, you are probably wanting the gRPC service to compute the Parcelable to respond with. For that, you need to pass a mutable API for the service to update.

  public static final Context.Key<AtomicReference<YourParcelable>> MY_KEY
      = Context.key("myparcelable"); // the string is just for debugging

  @Override
  public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
      ServerCall<ReqT, RespT> call,
      final Metadata requestHeaders,
      ServerCallHandler<ReqT, RespT> next) {
    // Context is immutable, so we put a mutable value inside it.
    final AtomicReference<YourParcelable> p = new AtomicReference<>();
    Context context = Context.current().withValue(MY_KEY, p);
    return Contexts.interceptCall(context, new SimpleForwardingServerCall<ReqT, RespT>(call) {
      @Override
      public void sendHeaders(Metadata responseHeaders) {
        YourParcelable yp = p.get();
        if (yp != null) {
          responseHeaders.put(CUSTOM_HEADER_KEY, yp);
        }
        super.sendHeaders(responseHeaders);
      }
    }, requestHeaders);
  }

// In the service implementation before sending a response:
MyInterceptor.MY_KEY.get().set(yourParcelable);
Eric Anderson
  • 24,057
  • 5
  • 55
  • 76
  • When I try this code, I am advised that I am unable to create a `SimpleForwardingServerCall` : the ctor appears to be protected. – Patrick Brennan Aug 07 '23 at 16:45
  • 1
    The constructor for SimpleForwardingServerCall is `protected`. So you have to extend the class. These classes here are anonymous classes extending SimpleForwardingServerCall. – Eric Anderson Aug 08 '23 at 22:45