解决protobuf-lua导入其他proto的BUG
2018-03-11 23:39
232 查看
BUG示例
protobuf-lua有个BUG:当import其他proto的消息类型时,会报错假如有两个proto:reward和mail。其中mail的proto导入了reward的消息类型reward.proto如下:
package reward; message Reward { optional uint32 money = 1; }1
2
3
4
5
mail.proto如下:
import "reward.proto"; package mail; message Mail { optional uint32 id = 1; optional reward.Reward reward = 2; }1
2
3
4
5
6
7
8
运行的代码,如下:
--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)1
2
3
4
5
6
7
8
9
10
11
12
非常简单的代码,但很不幸报错。[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; }1
2
3
4
5
6
7
运行代码:
--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)1
2
3
4
5
6
7
8
9
10
11
12
13
14
报错:[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平台下的生成方式)1
2
生成 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/22github里的几位大神好久没维护了,那几个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('.', '_')1
2
3
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()1
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()1
经过这三点修改,又跑了一遍那两个例子,完美通过。结果就不贴了。如果有错的地方,欢迎指正。
相关文章推荐
- 解决protobuf-lua导入其他proto的BUG
- <转>IE6浏览器网页文字溢出的解决办法(重复字符bug)---隐藏float对其他float造成影响
- android导入工程缺少R文件解决办法 和其他的不一样
- 解决protobuf不能直接在IOS上使用,利用protobuf-net在IOS上通讯
- Eclipse cdt解决github导入的项目无法打开声明的bug (cannot open declaration)
- eclipse打开或导入其他项目时乱码的解决方法
- Extjs 中实现combox多选,已经解决了原有的bug 【选择多条记录后,鼠标点击其他空白处,选择的数据丢失,】
- Android导入其他工程时报错的解决方法探索
- android studio导入其他项目工程报错解决方法
- 解决bug:在eclipse中导入Android项目时报错: “invalid resource directory name bin/res/crunch”
- (---关于oracle服务器和客户端字符集---)导出的pde是正常的(因为通过其他的plsql中导入没有问题),但是通过plsql导入后,显示乱码,怎么解决?
- eclipse导入Java web项目,项目名出现红叉而其他地方没有红叉的问题解决方法
- SLua 绑定 Protobuf-Lua (protoc-gen-lua) 在SLua中使用 Protobuf
- 曲线解决CMFCPropertyGridCtrl掩码的bug2009年12月30日 星期三 下午 01:24CMFCPropertyGridCtrl这个控件当用到掩码时,会有问题.解决办法用其他掩码替代.下面是一个IP掩码处理方法.代码如下
- 解决导入其他项目时文件乱码
- 解决ECSHOPdz bug ,无法与其他产品同步退出
- protobuf-gen-lua 不能支持int64 的解决方法 !!
- eclipse导入Java web项目,项目名出现红叉而其他地方没有红叉的问题解决方法
- 解决protobuf数据丢失bug
- 解决公务车Bug:停车费管理中导入停车费用时报数据库操作异常