Source:
<code>public <ReqT , RespT> ClientCall<ReqT, RespT> interceptCall( final MethodDescriptor<ReqT, RespT> method, final CallOptions callOptions, final Channel delegateChannel) { if (resourceLimiter == null) { return delegateChannel.newCall(method, callOptions); } return new ForwardingClientCall<ReqT, RespT>() { private ClientCall.Listener<RespT> delegateListener = null; private ClientCall<ReqT, RespT> delegateCall; private Metadata headers; private int requested; private Long id = null; @Override public void start(ClientCall.Listener<RespT> listener, Metadata headers) { this.delegateListener = listener; this.headers = headers; } @Override public void request(int numMessages) { if (id == null) { requested += numMessages; } else { delegate().request(numMessages); } } @Override public void sendMessage(ReqT message) { Preconditions.checkState(delegateCall == null); Preconditions.checkState(delegateListener != null); Preconditions.checkState(headers != null); <START> Preconditions.checkState(id == null); <END> try { id = resourceLimiter .registerOperationWithHeapSize(((MessageLite) message).getSerializedSize()); } catch (InterruptedException e) { delegateListener.onClose(Status.INTERNAL.withDescription("Operation was interrupted"), new Metadata()); return; } delegateCall = delegateChannel.newCall(method, callOptions); SimpleForwardingClientCallListener<RespT> markCompletionListener = new SimpleForwardingClientCallListener<RespT>(this.delegateListener) { public void onClose(io.grpc.Status status, Metadata trailers) { resourceLimiter.markCanBeCompleted(id); delegate().onClose(status, trailers); } }; delegate().start(markCompletionListener, headers); delegate().request(requested); delegate().sendMessage(message); } @Override protected ClientCall<ReqT, RespT> delegate() { return delegateCall; } }; }</code><technical_language>Please add a message id null. "This interceptor supports unary calls"</technical_language>

Target:
public <ReqT , RespT> ClientCall<ReqT, RespT> interceptCall( final MethodDescriptor<ReqT, RespT> method, final CallOptions callOptions, final Channel delegateChannel) { if (resourceLimiter == null) { return delegateChannel.newCall(method, callOptions); } return new ForwardingClientCall<ReqT, RespT>() { private ClientCall.Listener<RespT> delegateListener = null; private ClientCall<ReqT, RespT> delegateCall; private Metadata headers; private int numMessagesRequested = 0; private Long id = null; @Override public void start(ClientCall.Listener<RespT> listener, Metadata headers) { this.delegateListener = listener; this.headers = headers; } @Override public void request(int numMessages) { if (id == null) { numMessagesRequested += numMessages; } else { delegate().request(numMessages); } } @Override public void sendMessage(ReqT message) { Preconditions.checkState(delegateCall == null, "ThrottlingClientInterceptor only supports unary operations"); Preconditions.checkState(id == null, "ThrottlingClientInterceptor only supports unary operations"); Preconditions.checkState(delegateListener != null, "start() has to be called before sendMessage()."); Preconditions.checkState(headers != null, "start() has to be called before sendMessage()."); try { id = resourceLimiter .registerOperationWithHeapSize(((MessageLite) message).getSerializedSize()); } catch (InterruptedException e) { delegateListener.onClose(Status.INTERNAL.withDescription("Operation was interrupted"), new Metadata()); return; } delegateCall = delegateChannel.newCall(method, callOptions); SimpleForwardingClientCallListener<RespT> markCompletionListener = new SimpleForwardingClientCallListener<RespT>(this.delegateListener) { public void onClose(io.grpc.Status status, Metadata trailers) { resourceLimiter.markCanBeCompleted(id); delegate().onClose(status, trailers); } }; delegate().start(markCompletionListener, headers); delegate().request(numMessagesRequested); delegate().sendMessage(message); } @Override protected ClientCall<ReqT, RespT> delegate() { return delegateCall; } }; }