openapiv2导入在生成的代码中导致编译错误



我使用buf来生成几种语言(go, python, js, java, c#)的grpc服务器和客户端代码,同时使用grpc-ecosystem/plugins/openapiv2插件从相同的proto文件生成swagger文档。

在一些文件中,我使用customoption (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_tag) = {description: "Manage datasets and examples used for training."};向文档中添加额外的元数据。这需要我从grpc-gateway项目导入annotations.proto,这导致导入也出现在生成的源文件中。现在像go这样的语言可以通过使用import来处理副作用

import (
_ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options"
_ "google.golang.org/genproto/googleapis/api/annotations"
)

但是在Java和c#中有一些生成的行看起来像这样

registry.add(com.google.api.AnnotationsProto.http);
registry.add(grpc.gateway.protoc_gen_openapiv2.options.Annotations.openapiv2Tag);

导致编译错误,因为grpc.gateway...包不存在(我能够通过Maven和nuget导入googleapi包)。当我从.proto文件中删除选项时,就没有问题了,我可以将源文件编译成一个包进行分发。有没有办法从生成的代码中排除这些导入?

我已经尝试将文档分离到它自己的文件,但这是不可能的元数据,这是服务或消息定义的一部分,因为我得到重复的定义错误。

由于没有与该annotations.proto文件对应的官方Java库,因此在生成Java代码之前,您需要生成自己的库或做一些修改编译后的描述符的操作。

  1. 您可以为annotations.proto生成Java代码,而不仅仅是您自己的原型来导入它。

    如果您使用Buf,您实际上可以告诉它使用--include-imports标记到buf generate来为您的导入生成源代码(尽管这会为所有导入生成源代码,而不仅仅是那些没有相应Java库的导入)。

    这些注释在Buf的Schema Registry中可用,因此您也可以单独生成这些文件,并使用buf generate buf.build/grpc-ecosystem/grpc-gateway将它们编译成一个单独的JAR。

    这个文件的一个问题是它没有在文件中声明Java包选项。这就是生成代码中的Java包没有正确的反向域名的原因。使用Buf,您可以使用托管模式来实际注入Java包选项,以将这些文件生成到您想要的任何包中(因此您可以像在"阴影"中一样生成它们;

  2. 第二个路径不太推荐,也不适合胆小的人,但它允许您省略生成代码中的导入。首先需要将源代码编译为文件描述符集。(但可以通过buf build;对于protoc,使用-o选项而不是--java_out。)该文件是一个二进制编码的FileDescriptorSet。

    你可以写一些东西来读取这个文件(将它的内容解组成一个FileDescriptorSet),然后修改它。您可以通过检查集合中每个文件的依赖项字段并删除像"protoc-gen-openapiv2/options/annotations.proto"这样的条目来修改它。

    然后,您可以将其重新封送到一个文件中,并将其反馈给代码生成。因此,不是从源代码生成Java代码,而是从修改后的描述符集生成它们(如果使用Buf,则使用buf generate <file>#format=bin,如果使用protoc,则使用protoc --descriptor_set_in=<file> --java_out=<output-dir>)。

    注意,这种方法只有在使用被删除的导入的东西都是自定义选项时才能工作。这是因为自定义选项可以安全地表示为描述符中无法识别的字段(并且可以有效地忽略)。如果删除具有在文件中引用的类型定义的导入,编译器将不接受修改后的文件描述符集。

如果最后一个项目看起来像希腊语,那是因为它是相当高级的描述符修饰。实际上,我认为第一个项目是你最好的方法。

最新更新