Skip to content

Since 1.70.0, generated code fails to compile when certain streaming service method names conflict #12331

@doughd

Description

@doughd

Summary

Since release 1.70.0, you cannot have a streaming gRPC method named Notify because the generated code creates a notify() method which tries to override the final Object.notify().

What version of gRPC-Java are you using?

1.69.1 and misc earlier - example works
1.70.0, 1.75.0 (likely all between those) - example fails to compile

What is your environment?

Linux. Corretto 17.

What did you expect to see?

With this diff to add a streaming Notify method in the example:

% cat <<EOF > notify-bug
--- a/examples/src/main/proto/hello_streaming.proto
+++ b/examples/src/main/proto/hello_streaming.proto
@@ -24,6 +24,8 @@ package manualflowcontrol;
 service StreamingGreeter {
   // Streams a many greetings
   rpc SayHelloStreaming (stream HelloRequest) returns (stream HelloReply) {}
+
+  rpc Notify(stream HelloRequest) returns (stream HelloReply) {}
 }

 // The request message containing the user's name.
EOF

Running ./gradlew installdist should succeed.

What did you see instead?

Versions 1.70.0 and later fail because they're conflicting with Object.notify.

% ./gradlew installDist                                                                                              

> Task :compileJava FAILED
.../grpc-java/examples/build/generated/sources/proto/main/grpc/io/grpc/examples/manualflowcontrol/StreamingGreeterGrpc.java:252: error: notify() in StreamingGreeterBlockingV2Stub cannot override notify() in Object
        notify() {
        ^
  overridden method is final
Note: .../grpc-java/examples/src/main/java/io/grpc/examples/customloadbalance/CustomLoadBalanceClient.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
1 error

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':compileJava'.
> Compilation failed; see the compiler error output for details.

The generated code (build/generated/sources/proto/main/grpc/io/grpc/examples/manualflowcontrol/StreamingGreeterGrpc.java) looks like:

  public static final class StreamingGreeterBlockingV2Stub
      extends io.grpc.stub.AbstractBlockingStub<StreamingGreeterBlockingV2Stub> {
// ...
    @io.grpc.ExperimentalApi("https://github.com/grpc/grpc-java/issues/10918")
    public io.grpc.stub.BlockingClientCall<io.grpc.examples.manualflowcontrol.HelloRequest, io.grpc.examples.manualflowcontrol.HelloReply>
        notify() {
      return io.grpc.stub.ClientCalls.blockingBidiStreamingCall(
          getChannel(), getNotifyMethod(), getCallOptions());
    }
  }

Version 1.69.1 and misc earlier versions that I checked succeeded because this V2 stub was introduced in 1.70.0.

Version 1.69.1 works because while it is named notify, it's not creating a zero arg notify():

% rg -A1 "notify" build
build/generated/source/proto/main/grpc/io/grpc/examples/manualflowcontrol/StreamingGreeterGrpc.java
146:    default io.grpc.stub.StreamObserver<io.grpc.examples.manualflowcontrol.HelloRequest> notify(
147-        io.grpc.stub.StreamObserver<io.grpc.examples.manualflowcontrol.HelloReply> responseObserver) {
--
198:    public io.grpc.stub.StreamObserver<io.grpc.examples.manualflowcontrol.HelloRequest> notify(
199-        io.grpc.stub.StreamObserver<io.grpc.examples.manualflowcontrol.HelloReply> responseObserver) {
--
279:          return (io.grpc.stub.StreamObserver<Req>) serviceImpl.notify(
280-              (io.grpc.stub.StreamObserver<io.grpc.examples.manualflowcontrol.HelloReply>) responseObserver);

Steps to reproduce the bug

Using examples from the latest release:

% git clone https://github.com/grpc/grpc-java.git
% cd grpc-java
% git checkout -b test-1-75-0 v1.75.0
% cd examples

Try it without changes as a baseline:

% ./gradlew installDist
% ./gradlew clean

Apply the change that shows the bug:

% cat <<EOF > notify-bug
--- a/examples/src/main/proto/hello_streaming.proto
+++ b/examples/src/main/proto/hello_streaming.proto
@@ -24,6 +24,8 @@ package manualflowcontrol;
 service StreamingGreeter {
   // Streams a many greetings
   rpc SayHelloStreaming (stream HelloRequest) returns (stream HelloReply) {}
+
+  rpc Notify(stream HelloRequest) returns (stream HelloReply) {}
 }

 // The request message containing the user's name.
EOF

% patch -p2 < notify-bug

Re-run with the proto change and it fails

% ./gradlew installDist 

> Task :compileJava FAILED
.../grpc-java/examples/build/generated/sources/proto/main/grpc/io/grpc/examples/manualflowcontrol/StreamingGreeterGrpc.java:252: error: notify() in StreamingGreeterBlockingV2Stub cannot override notify() in Object
        notify() {
        ^
  overridden method is final
1 error

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':compileJava'.
> Compilation failed; see the compiler error output for details.

* Try:
> Run with --info option to get more log output.
> Run with --scan to get full insights.

BUILD FAILED in 871ms

% ./gradlew clean

It fails in 1.70.0 too:

% git stash
% git checkout -b test-1-70-0 v1.70.0

# Builds normally
% ./gradlew installDist
% ./gradlew clean

# Fails with this change
% git stash pop
% git diff

% ./gradlew installDist
% ./gradlew clean

However, with the last release before 1.70.0 (1.69.1) it works:

% git stash
% git checkout -b test-1-69-1 v1.69.1

# Try without changes
% ./gradlew installDist
% ./gradlew clean

# Try with changes to show it still succeeds
% git stash pop
% git diff

% ./gradlew installDist

If you redo the above but name the gRPC method Notify2 so it doesn't conflict with Object.notify, all three grpc-java releases work.

Suspected commit

I suspect it is due to this commit in 1.70.0:

stub: Introduce new API: BlockingStubV2 which supports Bidi streaming, Client streaming, a cleaner Server streaming and Unary RPCs (#10318) (ea8c31c)

It looks like it is lower casing the name without mangling it in case of conflicts like notify. e.g. it creates java methods sayHelloStreaming() and notify() when the gRPC service methods are named SayHelloStreaming and Notify.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions