protobuf java 反射

本文介绍了如何使用Java和protobuf的反射功能,将HBase中存储的数据转换为protobuf message并导出。通过定义protobuf message,使其字段与HBase列名对应,获取HBase列的value并填充到对应字段,最后将构造好的message写入文件。此过程旨在实现通用且可配置的数据处理方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

需求:

线上需要一份数据,这份数据是存储在hbase中的(比如对于某一个实体,其各个字段是存储在hbase的各个列的)。而希望最终导出的文件的每一行是一个 protobuf 的message,以方便解析和维护。

具体做法:

定义一个 protobuf  message,其各个 field 的名字与 hbase 各列的 key 的名字对应,将 hbase 中各列对应的 value 取出来,填充到对应的 field 中,生成构造完成的message之后, dump 到文件。

利用 java 和 protobuf 的反射功能,将该功能做成通用可配置的,而不是针对每个字段都调用对应的 set 函数。

以下记录碰到的坑。


            Class cl = Class.forName(pbClassName);    // 首先根据 pb message class 名称得到 Class 对象。(坑1:注意内部类连接符为$,如 package_name.class_name$inner_class_name, 另外注意脚本启动的时候要注意对 $ 转义,否则 shell 会以为 $inner_class_name 为变量)
            Method method = cl.getMethod("newBuilder");    // newBuilder 为静态变量,即使没有 message 的具体实例也可以 invoke!yes!
            Object obj = method.invoke(null, null);
            Message.Builder msgBuilder = (Message.Builder)obj;       // 得到 builder
            Descriptors.Descriptor descriptor = msgBuilder.getDescriptorForType();   // 得到 descriptor

以下比较直观了:

            for(Map.Entry<String, String> entry : keyValueMap.entrySet()) {    // <span style="font-family: Arial, Helvetica, sans-serif;">keyValueMap 为从 hbase 取出的各列 key 和 value</span> 
                Descriptors.FieldDescriptor filedDescriptor = descriptor.findFieldByName(entry.getKey());
                if(filedDescriptor == null) {
                    continue;
                }
                boolean isRepeated = filedDescriptor.isRepeated();
                Descriptors.FieldDescriptor.JavaType type = filedDescriptor.getJavaType();
                if (isRepeated) {
                    String value = entry.getValue();
                    String[] strArray = value.split(",");
                    for(int i = 0; i < strArray.length; ++i) {
                        Object valueObject = getObject(strArray[i], type);    //  getObject 见下
                        if (valueObject == null) {
                            continue;
                        }
                        msgBuilder.addRepeatedField(filedDescriptor, valueObject);
                    }
                } else {
                    Object valueObject = getObject(entry.getValue(), type);
                    if (valueObject == null) {
                        continue;
                    }
                    msgBuilder.setField(filedDescriptor, getObject(entry.getValue(), type));
                }
            }
            Message msg = msgBuilder.build();

    private static Object getObject(String rawString, Descriptors.FieldDescriptor.JavaType type) {
        try {
            switch (type) {
                case INT:
                    return Integer.valueOf(rawString);
                case LONG:
                    return Long.valueOf(rawString);
                case FLOAT:
                    return Float.valueOf(rawString);
                case DOUBLE:
                    return Double.valueOf(rawString);
                case BOOLEAN:
                    return Boolean.valueOf(rawString);
                case STRING:
                    return rawString;
                default:
                    // BYTE_STRING, ENUM, MESSAGE                     哈哈先支持以上这些啦
                    return null;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

另要输出文件,将pb base64 编码,否则直接输出会有换行符,按行解析不方便。

                byte[] pbByte = pbMessage.toByteArray();          // 坑3: 将 proto 定义文件生成 java 文件的 protoc 文件的版本要与 java 工程 protobuf 的 jar 版本一致,否则会报错。
                pbStr = new String(Base64.encodeBase64(pbByte), "UTF-8");



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值