解决protobuf-lua导入其他proto的BUG
来源:互联网 发布:淘宝好的名牌原单店 编辑:程序博客网 时间:2024/05/29 17:25
BUG示例
protobuf-lua有个BUG:
当import其他proto的消息类型时,会报错
假如有两个proto:reward和mail。
其中mail的proto导入了reward的消息类型
reward.proto如下:
package reward; message Reward { optional uint32 money = 1; }
mail.proto如下:
import "reward.proto"; package mail; message Mail { optional uint32 id = 1; optional reward.Reward reward = 2; }
运行的代码,如下:
--optional运行代码 -- 发送 -- local sendMail = mail_pb.Mail() sendMail.id = 12 local reward = sendMail.reward reward.money = 30 printf(sendMail) -- 模拟接收 -- local recvMail = mail_pb.Mail() recvMail:ParseFromString(sendMail:SerializeToString()) printf(recvMail)
非常简单的代码,但很不幸报错。
[string “protobuf.lua”]:363: attempt to index upvalue ‘message_type’ (a nil value)
Reward这个消息类型如果定义在Mail中是不会报错的,但是一旦通过其他proto的方式导入时,就会出现上述错误。
同样地,将字段的optional类型改成repeated类型,也会报错。代码和示例如下:
mail.proto:
import "reward.proto"; package mail; message Mail { optional uint32 id = 1; repeated reward.Reward reward = 2; }
运行代码:
--repeated运行代码 -- 发送 -- local sendMail = mail_pb.Mail() sendMail.id = 12 for i=1,10 do local reward = sendMail.reward:add() reward.money = 30+i end printf(sendMail) -- 模拟接收 -- local recvMail = mail_pb.Mail() recvMail:ParseFromString(sendMail:SerializeToString()) printf(recvMail)
报错:
[string “containers.lua”]:27: attempt to call field ‘_concrete_class’ (a nil value)
检查了一圈,发现其实proto-lua根本就没有考虑过导入其他proto情况;他默认的消息类型都是在本地。
查看他自动生成的lua文件就能看出。
通过
protoc.exe --plugin=protoc-gen-lua="XXX\protoc-gen-lua.bat" --lua_out=XX\YourOutDir -I=XXX\InputDir XX\InputDir\reward.proto XX\InputDir\mail.proto(windows平台下的生成方式)
生成 mail_pb.lua 和 reward_pb.lua文件。
其中mail_pb.lua截图如下:
检查发现,REWARD_PB_REWARD
这个消息类型根本就不存在!怪不得会报nil错误。
解决方案
想到的解决方案有两种:
1.将reward_pb里的REWARD类型挂到reward_pb下,而不是作为局部变量
2.将REWARD_PB_REWARD
改成reward_pb.Reward,并修改相应代码
github上已经有第一种方法的实现,链接如下“:
https://github.com/sean-lin/protoc-gen-lua/pull/7
此种方法虽然能够解决问题,但个人觉得太过暴力。原作者可能并不希望MAIL、REWARD等等这种大写的消息类型暴露到外面,此外,也会增加初学者的困惑:我到底是用Mail呢还是MAIL呢?
为了保留作者的初衷,我用了第二种方法实现。
需要改三个文件:
1.protoc-gen-lua (改变自动生成的规则,目的将
REWARD_PB_REWARD
改成reward_pb.Reward)
2.protobuf.lua (修改optional的发送和接受)
3.containers.lua (修改repeated的add函数)
下面分别讲解每个文件的主要的修改内容,具体的细节实现我放到了github上,链接如下:
https://github.com/sean-lin/protoc-gen-lua/pull/22
github里的几位大神好久没维护了,那几个pullrequest都没处理。所以可能还得你们自己动手改。
1.protoc-gen-lua修改
判断field_desc是否来自别的包,是则不变;不是则换成大写。
代码如下:
type_name = env.get_ref_name(field_desc.type_name) if not type_name.split('.')[0] in [filename+"_pb" for filename in includes]: type_name = type_name.upper().replace('.', '_')
2.protobuf.lua修改
protobuf-lua在实现中分了两种对象类型来区分消息和域,分别是Message和Descriptor。
像MAIL和REWARD属于Descriptor,但Mail和Reward属于Message。
如果REWARD类型换成Reward类型,可想而知他的对象类型也发生了变化,从Descriptor变成了Message。
研究源码可以发现如果某个消息的域用了其他消息类型,比如MAIL用了REWARD。那么他会去调用REWARD._concrete_class来创建消息对象,调用形式类似:REWARD._concrete_class()
那REWARD._concrete_class是个什么东东呢?
检查发现他居然是Reward!
Reward是Message类型,是可以直接调用的。因为他在元表里写了__call函数,所以可以直接调用。这也是为什么我们可以用mail_pb.Mail()创建Mail消息对象的原因。
另外Message类型是没有_concrete_class这个字段的。
所以修改方案很明确,只要将REWARD._concrete_class() 换成 Reward()即可。
找到报错的地方(有两处,分别在发送和接收的代码里):message_type._concrete_class(),换成如下:
(message_type._concrete_class and message_type._concrete_class()) or message_type()
3.containers.lua修改
optional需要对消息接发收都要修改,但对于repeated,只需要修改一处,即在containers.lua里的add函数里。这是因为repeated的域不直接参与到消息的接收发送过程,只要保证创建的对象正确即可。
修改方式也是类似,将message_descriptor._concrete_class(),换成:
(message_descriptor._concrete_class and message_descriptor._concrete_class()) or message_descriptor()
经过这三点修改,又跑了一遍那两个例子,完美通过。结果就不贴了。如果有错的地方,欢迎指正。
- 解决protobuf-lua导入其他proto的BUG
- protobuf 一个.proto 文件的简单讲解
- 解决protobuf数据丢失bug
- protobuf引入不同包下的proto文件
- protobuf 与lua的结合
- RecyclerView导入bug解决
- protobuf 消息升级 && 动态proto
- lua-proto动态解析
- .proto 转换成 .lua
- protoc-gen-lua多个proto嵌套的实现
- Proto-gen-lua 与 C# 对 Extension 的不同处理
- proto-gen AS3版本的protobuf extension反序列化错误解决方法
- protobuf-net 将 .proto 文件转换成 .cs 文件的方法
- 【protobuf进阶】通过.proto文件导出C#支持的.cs类文件
- 推荐个protobuf的lua版
- cocos2dx中protobuf的lua使用
- protobuf lua 和c++的区别
- java 及lua proto 生成
- LeetCode -- Binary Tree Paths
- div模型
- strace调试(Linux Device Driver)
- HDU 2438 (三分)
- 个人主页
- 解决protobuf-lua导入其他proto的BUG
- LeetCode -- Bulls and Cows
- 获取TextView的高度
- MarkdownPad2如何使用空格
- 模拟输入H.264流,输出封装格式文件
- Libcap 文件格式
- LeetCode -- Game of Life
- AS3三种缩放方式的区别
- Hadoop集群(第7期)_Eclipse开发环境设置