使用antlr4, 用ts/js还原protobuf生成的java代码为pb (四)

目录:

  • 使用antlr4, 用ts/js还原protobuf生成的java代码为pb (一)
  • 使用antlr4, 用ts/js还原protobuf生成的java代码为pb (二)
  • 使用antlr4, 用ts/js还原protobuf生成的java代码为pb (三)
  • 使用antlr4, 用ts/js还原protobuf生成的java代码为pb (四)
  • 使用antlr4, 用ts/js还原protobuf生成的java代码为pb (五)

仔细分析java代码

package msf.msgsvc;

import com.xxx.pb.MessageMicro;
import com.xxx.pb.PBField;
import com.xxx.pb.PBUInt32Field;
import com.xxx.pb.PBUInt64Field;

public final class msg_svc$PbDeleteMsgReq$MsgItem
extends MessageMicro {
    static final MessageMicro.FieldMap __fieldMap__ = 
            MessageMicro.initFieldMap(
                    (int[])new int[]{8, 16, 24, 32, 40}, 
                    (String[])new String[]{"from_uin", "to_uin", "msg_type", "msg_seq", "msg_uid"}, 
                    (Object[])new Object[]{0, 0, 0, 0, 0}, msg_svc$PbDeleteMsgReq$MsgItem.class
            );
    public final PBUInt64Field from_uin = PBField.initUInt64((long)0);
    public final PBUInt32Field msg_seq = PBField.initUInt32((int)0);
    public final PBUInt32Field msg_type = PBField.initUInt32((int)0);
    public final PBUInt64Field msg_uid = PBField.initUInt64((long)0);
    public final PBUInt64Field to_uin = PBField.initUInt64((long)0);
}
序号/PB字段类型(tags) 字段名称(fields) defaultValues
1/0->8 from_uin 0
2/0->16 to_uin 0
3/0->24 msg_type 0
4/0->32 msg_seq 0
5/0->40 msg_uid 0

序号/PB字段类型, 这里序号命名为A, 字段类型为B. 序列化公式为 A<<3|B.

google protobuf类型参考

Type Meaning Used For
0 Varint int32, int64, uint32, uint64, sint32, sint64, bool, enum
1 64-bit fixed64, sfixed64, double
2 Length-delimited string, bytes, embedded messages, packed repeated fields
3 Start group groups (deprecated)
4 End group groups (deprecated)
5 32-bit fixed32, sfixed32, float

好了, 直接贴代码吧, 随便写的草稿. 别跟着"学坏了"

import {JavaListener} from "../antlr/Java/JavaListener";
import {ParseTreeListener} from "antlr4ts/tree";
import {ArrayInitializerContext, ClassBodyDeclarationContext, JavaParser} from "../antlr/Java/JavaParser";

export class CustomJavaListener implements JavaListener {

    public state;

    public enterClassBodyDeclaration(ctx: ClassBodyDeclarationContext) {
        let flags = [], fields = [], defaultValues = [];

        let modifer = ctx.modifier().filter(modifier => {
            return modifier.text == 'static';
        });
        if (modifer.length == 0) return;

        let memberDeclaration = ctx.memberDeclaration();
        if (!memberDeclaration) return;

        let fieldClaration = memberDeclaration.fieldDeclaration();
        if (!fieldClaration) return;

        let type = fieldClaration.typeType().classOrInterfaceType();
        if (type.Identifier().pop().text != 'FieldMap')return;

        let variable = fieldClaration.variableDeclarators().variableDeclarator(0);
        if (variable.variableDeclaratorId().text != '__fieldMap__'
        ) {
            return;
        }

        let func = variable.variableInitializer().expression();
        if (func.expression(0).expression(0).primary().text != 'MessageMicro' &&
            func.expression(0).children[2].text != 'initFieldMap') {
            throw new Error('should be `MessageMicro.initFieldMap`');
        }

        let expressList = func.expressionList();

        flags = this.getArray(expressList.expression(0), 'int');

        fields = this.getArray(expressList.expression(1), 'String');

        defaultValues = this.getArray(expressList.expression(2), 'Object');

        console.log(flags, fields, defaultValues);
    }

    getArray(express2, type) {
        let rtn = [];
        if (express2.typeType().text != `${type}[]`) {
            throw new Error(`express 0 should be ${type}[]`)
        } else if (express2.expression(0).children[0].text != 'new' &&
            express2.expression(0).children[1].getChild(0).text != `${type}`
        ) {
            throw new Error('express 0 should be new string ')
        } else {
            let arrayCreatorRest = express2.expression(0).children[1].getChild(1);
            let arrayInitializer: ArrayInitializerContext = arrayCreatorRest.getChild(arrayCreatorRest.childCount - 1);
            arrayInitializer.variableInitializer().map(variable => {

                let v;
                if (type.toLowerCase() == 'int') {
                    v = parseInt(variable.text);
                } else if (type.toLowerCase() == 'string') {
                    v = variable.text.replace(/'(.+?)'|"(.+?)"/g, "$1$2");
                } else {
                    v = variable.text;
                }
                rtn.push(v);
            })
        }
        return rtn;
    }
}

最后再写一点校验代码, 以及最终生成protobuf的代码吧, 我相信对树的遍历大家应该都会写吧

上面是对这个特定的树进行的粗略遍历, 有时树会多出一个父节点, 那么用固定的 A->children[0]->children[0]肯定是不行的. 比如getArray方法里用了express2.expression(0).children[0]有时这个节点根本是不存在的, 不可能为每个文件写个处理, 所以我们还是按标准方式来做吧.

现在我再来用visitor来完善树的遍历. visitor里可以实现针对规则或是打了标签的grammar的接口.( 默认的java.g4 grammar是没有打标签的, 我们修改一下将可以很快完成我们的工作. 在后面章节再做说明)

你可能感兴趣的:(使用antlr4, 用ts/js还原protobuf生成的java代码为pb (四))