Search code examples
javaprotocol-buffersgrpcnoclassdeffounderrornosuchmethoderror

NoSuchMethodException and NoClassDefFoundError in grpc protobuf java


I have a gRPC service that I launch, all good no errors. However, when I try to use grpcui (./grpcui -plaintext localhost:9900) that will read and to the service, I get the following:

Exception in thread "grpc-default-executor-0" java.lang.NoSuchMethodError: com.google.protobuf.Descriptors$FileDescriptor.internalBuildGeneratedFileFrom([Ljava/lang/String;[Lcom/google/protobuf/Descriptors$FileDescriptor;)Lcom/google/protobuf/Descriptors$FileDescriptor;
    at io.grpc.reflection.v1alpha.ServerReflectionProto.<clinit>(ServerReflectionProto.java:103)
    at io.grpc.reflection.v1alpha.ServerReflectionGrpc$ServerReflectionBaseDescriptorSupplier.getFileDescriptor(ServerReflectionGrpc.java:234)
    at io.grpc.protobuf.services.ProtoReflectionService$FileDescriptorIndex.<init>(ProtoReflectionService.java:418)
    at io.grpc.protobuf.services.ProtoReflectionService$ServerReflectionIndex.<init>(ProtoReflectionService.java:339)
    at io.grpc.protobuf.services.ProtoReflectionService.updateIndexIfNecessary(ProtoReflectionService.java:97)
    at io.grpc.protobuf.services.ProtoReflectionService.serverReflectionInfo(ProtoReflectionService.java:136)
    at io.grpc.reflection.v1alpha.ServerReflectionGrpc$MethodHandlers.invoke(ServerReflectionGrpc.java:220)
    at io.grpc.stub.ServerCalls$StreamingServerCallHandler.startCall(ServerCalls.java:224)
    at io.grpc.internal.ServerImpl$ServerTransportListenerImpl.startWrappedCall(ServerImpl.java:648)
    at io.grpc.internal.ServerImpl$ServerTransportListenerImpl.startCall(ServerImpl.java:626)
    at io.grpc.internal.ServerImpl$ServerTransportListenerImpl.access$1900(ServerImpl.java:417)
    at io.grpc.internal.ServerImpl$ServerTransportListenerImpl$1StreamCreated.runInternal(ServerImpl.java:556)
    at io.grpc.internal.ServerImpl$ServerTransportListenerImpl$1StreamCreated.runInContext(ServerImpl.java:531)
    at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
    at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:123)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

and

Exception in thread "grpc-default-executor-1" java.lang.NoClassDefFoundError: Could not initialize class io.grpc.reflection.v1alpha.ServerReflectionProto
    at io.grpc.reflection.v1alpha.ServerReflectionGrpc$ServerReflectionBaseDescriptorSupplier.getFileDescriptor(ServerReflectionGrpc.java:234)
    at io.grpc.protobuf.services.ProtoReflectionService$FileDescriptorIndex.<init>(ProtoReflectionService.java:418)
    at io.grpc.protobuf.services.ProtoReflectionService$ServerReflectionIndex.<init>(ProtoReflectionService.java:339)
    at io.grpc.protobuf.services.ProtoReflectionService.updateIndexIfNecessary(ProtoReflectionService.java:97)
    at io.grpc.protobuf.services.ProtoReflectionService.serverReflectionInfo(ProtoReflectionService.java:136)
    at io.grpc.reflection.v1alpha.ServerReflectionGrpc$MethodHandlers.invoke(ServerReflectionGrpc.java:220)
    at io.grpc.stub.ServerCalls$StreamingServerCallHandler.startCall(ServerCalls.java:224)
    at io.grpc.internal.ServerImpl$ServerTransportListenerImpl.startWrappedCall(ServerImpl.java:648)
    at io.grpc.internal.ServerImpl$ServerTransportListenerImpl.startCall(ServerImpl.java:626)
    at io.grpc.internal.ServerImpl$ServerTransportListenerImpl.access$1900(ServerImpl.java:417)
    at io.grpc.internal.ServerImpl$ServerTransportListenerImpl$1StreamCreated.runInternal(ServerImpl.java:556)
    at io.grpc.internal.ServerImpl$ServerTransportListenerImpl$1StreamCreated.runInContext(ServerImpl.java:531)
    at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
    at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:123)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

My service:

public class OneSideInitiated extends SideGrpc.SideImplBase {

    @Override
    public void requestStart(RemoteStartRequest request,
                                        StreamObserver<RemoteStartResponse> responseObserver) {

        RemoteStartResponse response = RemoteStartResponse.newBuilder().build();

        responseObserver.onNext(response);
        responseObserver.onCompleted();
    }
}

The class that launches the service:

import io.grpc.Server;
import io.grpc.ServerBuilder;
import io.grpc.protobuf.services.ProtoReflectionService;

public class StuffServer {

    private Server server;

    public StuffServer(int port) {

        this.server = ServerBuilder.forPort(port)
                .addService(ProtoReflectionService.newInstance())
                .addService(new OneSideInitiated())
                .build();
    }

    public void start() throws IOException {
        server.start();
    }

    public void stop() throws InterruptedException {...}

    public static void main(String[] args) throws Exception {
        CccpServer cccpServer = new StuffServer(9900);
        cccpServer.start();
        cccpServer.blockUntilShutdown();
    }

    private void blockUntilShutdown() throws InterruptedException {...}
}

My Maven dependencies are:

        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-stub</artifactId>
            <version>1.26.0</version>
        </dependency>

        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-core</artifactId>
            <version>1.26.0</version>
        </dependency>

        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-netty</artifactId>
            <version>1.26.0</version>
        </dependency>

        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-services</artifactId>
            <version>1.26.0</version>
        </dependency>

        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>23.6.1-jre</version>
        </dependency>

        <dependency>
            <groupId>com.google.api.grpc</groupId>
            <artifactId>proto-google-common-protos</artifactId>
            <version>0.1.9</version>
        </dependency>

        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-testing</artifactId>
            <version>1.26.0</version>
            <scope>testing</scope>
        </dependency>

Have tried different combinations of guava and io.grpc versions, didn't make any difference. Anyone got any ideas on this?


Solution

  • That particular FileDescriptor.internalBuildGeneratedFileFrom() method was added to Protobuf in v3.8. Generally NoSuchMethodError errors are caused dependencies being downgraded, commonly by Maven.

    You can run mvn dependency:tree to check what versions of dependencies are being used. In this case you will find that com.google.api.grpc:proto-google-common-protos:0.1.9 is depending on com.google.protobuf:protobuf-java:3.2.0 and that is the version Maven is using.

    The gRPC team recommends always using Maven Enforcer's requireUpperBoundDeps to detect when Maven is poorly choosing versions. You can add to your pom.xml:

        <plugins>
          ...
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-enforcer-plugin</artifactId>
            <version>1.4.1</version>
            <executions>
              <execution>
                <id>enforce</id>
                <goals>
                  <goal>enforce</goal>
                </goals>
                <configuration>
                  <rules>
                    <requireUpperBoundDeps/>
                  </rules>
                </configuration>
              </execution>
            </executions>
          </plugin>
        </plugins>
    

    When it detects a failure during build, it provides the versions being depended on elsewhere. Choose the largest version and add it as an explicit dependency to your project:

        <dependency>
          <groupId>com.google.protobuf</groupId>
          <artifactId>protobuf-java</artifactId>
          <version>3.11.0</version>
        </dependency>
    

    I'll also note that proto-google-common-protos:0.1.9 is very old. I'd recommend updating to a more recent version, like 1.17.0. Although you'd have still have experienced this problem with 1.17.0.