【问题标题】:NoSuchMethodException and NoClassDefFoundError in grpc protobuf javagrpc protobuf java中的NoSuchMethodException和NoClassDefFoundError
【发布时间】:2020-01-23 13:56:29
【问题描述】:

我启动了一个 gRPC 服务,一切都很好,没有错误。但是,当我尝试使用grpcui (./grpcui -plaintext localhost:9900) 来读取服务时,我得到以下信息:

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)

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)

我的服务:

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();
    }
}

启动服务的类:

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 {...}
}

我的 Maven 依赖项是:

        <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>

尝试了guavaio.grpc 版本的不同组合,没有任何区别。 有人对此有任何想法吗?

【问题讨论】:

    标签: java protocol-buffers grpc noclassdeffounderror nosuchmethoderror


    【解决方案1】:

    这个特定的 FileDescriptor.internalBuildGeneratedFileFrom() 方法在 v3.8 中被添加到 Protobuf。一般NoSuchMethodError 错误是由于依赖被降级导致的,通常是由 Maven 造成的。

    您可以运行mvn dependency:tree 来检查正在使用哪些版本的依赖项。在这种情况下,您会发现com.google.api.grpc:proto-google-common-protos:0.1.9 依赖于com.google.protobuf:protobuf-java:3.2.0,这是 Maven 使用的版本。

    gRPC 团队建议始终使用 Maven Enforcer 的requireUpperBoundDeps 来检测 Maven 何时错误地选择版本。您可以添加到您的 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>
    

    当它在构建过程中检测到故障时,它会提供其他地方依赖的版本。选择最大的版本并将其作为显式依赖项添加到您的项目中:

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

    我还会注意到 proto-google-common-protos:0.1.9 已经很老了。我建议更新到更新的版本,例如 1.17.0。尽管您在 1.17.0 中仍然会遇到此问题。

    【讨论】:

    • 非常翔实和详尽的答案,谢谢先生!你指出了问题;我使用的是旧版本的 grpc 来生成 java 文件。
    • gRPC 支持旧的生成代码。因此,如果您使用旧的 protoc-gen-grpc-java 可执行文件,事情应该仍然有效。
    猜你喜欢
    • 1970-01-01
    • 2018-06-28
    • 2017-03-18
    • 2021-05-07
    • 2019-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-22
    相关资源
    最近更新 更多