有人提 proposal 被拒了: github.com/protocolbuffers/protobuf/issues/9527#issue-1142821422
那像这种情况怎么搞?每个 response 都创建一个 wrapper ?
public class Response {

@NotNull
private ResponseStatus status;

private T result;

}

是的,非常恶心
也不支持继承
或者写 t4 生成😂

#1 写 t4 生成是啥意思

message {
bytes result = 1;
}

自己根据类型,将 result 解析成正确的类型。

proto 作为协议数据声明,支持范型意味着声明侵入编码和传输过程,本来就不合适。不支持才是合理的。否则人家 isser 说了使用 any 类型就好了啊

谁叫好好的响应数据非要包一层呢

用 string

支持泛型什么鬼,那和不支持泛型的语言怎么交互?

byte ?

#4 怎么定义协议?泛型说白了也就是个 message ,只不过是个动态的 message 而已。而且我觉得最恶心的一点是他们不仅不愿意支持这功能,而且还不愿意接受外部设计,连提 pr 的机会都不给。

#6 只是支持而已,你可以不用,也可以生成不含泛型的 sdk

#5 我在工作中看到的响应体都是这样设计的,看下你们的设计?

我确实没想到在一个不支持泛型的语言里要怎么用这个协议。这复杂度值得吗?

#11 没有泛型的语言直接去掉泛型就好了,泛型只是个语法糖

#8 协议只是约定,好比 protobuf 用 id 号指定字段,这个字段的类型只是双方约定信息,实际数据中不包含这个类型信息也不应该包含,你要加泛型就要在实际数据中包含类型信息,而这个类型实现过程各个语言支持不一样,已经产生了平台依赖,破坏了协议应该和实际实现无关的只是抽象约定的逻辑

如果你想说泛型类型信息也可以是双方约定,那么这和你申明类型是 any 然后任然需要另外一个字段在实际数据传输类型标记有何区别,如果你想说为何不可以把这个过程实现在基础库里,逻辑就是这个不符合基础库不应该包含非原子操作,好比 cpu 机器码不应该包含一个读取文件的高等级 api 一个逻辑,你想要你自己封装扩展就是了

不要把接口设计和程序逻辑混在一起,理解不到位也不要怪别人

去掉泛型,它的类型是什么?生成完的代码长啥样?而且这是藏逻辑,并不是好设计。

对,默认不支持。
我这边用的 golang ,我就把他改了,让 google.protobuf.Any 类型转换成了 interface{}。
你可以借鉴下( github.com/guoming0000/protobuf-go/commit/628f6211b3a75c96181c5137b1605fcfcedaaa4a ),然后改下 protobuf-java ,看看能不能满足你的需求。
不过这么改了就是非标了

github.com/go-kratos/kratos/issues/1952#issuecomment-1822297919

不要再包一层啦。

#14 取舍问题,openapi 就支持了

很简单,正常响应直接返回数据,http 状态吗 200 ;接口出错时,前端参数问题就用 400 状态码,服务器问题就用 500 ,然后响应结构:{"code": 业务定义的错误码, "msg": 错误描述或希望显示的文案}

前端 api 设计形式类似 static fetchItemById = (id: number, onError: (code: number, msg: string) => void): Promise => {...}

直接根据 http 状态码去解析,而不是先解析,再根据状态搞泛型

#16 没看懂,但是他这个问题不是加个 optional 就能进解决吗。。

这不是 oneof 的场景吗?

#18 这只适用于 http 接口,而且即使是 http 接口,我也认为这样并不好,把业务状态放在协议里了

#15 搞不了搞不了...没那个能力...我还是老老实实多写几个 wrapper 吧

并非只适用 http ,而是一种设计思路,websocket 、mqtt 也都可以用类似的设计。而且这并不是什么把业务状态放在协议里,http 协议的状态码本就希望服务器能够表达一些明确的意图,不管成功失败全用 200 才是自作聪明的反设计,曾经可能还有些场景有些理由这样做,现在可以扔掉这种惯性设计了。

而且我觉得最恶心的一点是他们不仅不愿意支持这功能,而且还不愿意接受外部设计,连提 pr 的机会都不给。

别人合理拒绝,却反过来说别人封闭,什么道理!
要都是随便接受外部设计和 pr ,各种项目早都得被乌合之众搞凉了!

protobuf 肯定不要支持泛型呀
它一个二进制格式描述协议,和泛型有毛关系

你 pb idl 怎么写的,贴一下呢。就是需要 Response1 、Response2 一个个描述
如果你想 result 一会儿是这个 一会儿是那个,那这个场景就不适合用 pb 。直接裸写就行了,然后用 Swagger 的 Inheritance and Polymorphism 能力

#24 好吧,我表达的有问题,不是说随便接受 pr 。开源项目的一大优势不就是可以倾听社区的声音吗?我意思是没必要这样毫无余地的就拒绝,如果社区呼声很高,也是可以考虑的吧。

#23 像“余额不足”这种业务情况如何用 status 表达,不还是得用自定义的 code 和 message

说到取舍,与其用泛型,这里最好的设计就是字段是 string 。这个取舍稍微想想就能选对了。

http 状态码 500 ,返回数据类似{"code": 610016, "msg": "余额不足"}
简单来说就是成功时 http 状态 200 ,响应数据直接是业务负载数据,错误时 http 状态非 200 ,然后响应数据返回业务错误码和信息文本

是具体是哪个 4xx 可能还可需要讨论,但肯定不该是 http 500 ...

#9 问题就在这"可“字上。项目集成,维护,切换组件过程中麻烦事就够多了。

好比别人 boolean 都是 true false, 你的项目为了灵活定义 boolean 可以是 true false ""。代码都是 python 写的毫无问题,跟 js 交互也没问题。现在要跟 java 交互,项目组肯定日常问候。

pb 这种就是不支持泛型的,就像 http 里一个接口返回的 json 内容里有个 list 的值可能为
[1,2,3,4]和["1","2","3"]的,你序列化难道不是要 case int 和 string 吗,这样叫泛型吗,泛型是编译推导代码内的类型后去做类型擦除的。
可以是任意类型的话那应该用 json rpc 啥的有个 id 和 id 对应 data body 之类的,以及使用一个 websocket 传输不一样数据结构的 socketio 协议。
你应该考虑用 oneof 或者 message id | message body 这种。或者把那段类型指定为 byte ,自己序列化

很正常的需求,不用怀疑自己。
写过一些组件就懂泛型的意义了。

它下面不是已经说理由了么,因为泛型太复杂了。如果要做泛型,那你需要做的不只是设计一套泛型语法,写一个看起来可行的实现,而是评估泛型在每一种 pb 可能交互的主流语言中使用会出现什么问题,在实现中解决这些问题,并给出一个健壮的测试集。又不是说你随便提个 PR 别人就必须得合的……

pb 不是有个类似于泛型的东西吗。

会在输出的时候额外加 type 来做标识。

我记错了?

#33

有意义确实不假,但问题是太过于复杂了。

pb 最开始走的那个以 codegen 为主的模式做泛型会很麻烦。

把泛型这个需要语言特性支持的东西放进 IDL 就不合适,给不支持泛型的语言 codegen 带来一堆麻烦。
any 或者 oneof 然后自己 cast 就好懂多了。
楼上提到几个魔改也只是特定语言 codegen 小改,没动 IDL 。