美文网首页grpc微服务框架探索
protobuf 与 Java 对象互转

protobuf 与 Java 对象互转

作者: go4awalk | 来源:发表于2019-04-02 00:57 被阅读0次

    Java使用protobuf时,往往需要在Java对象(比如POJO)和protobuf message的Java对象间互转:

    1. protobuf接口需要传入message参数: 把POJO转成message, 作为接口参数;
    2. protobuf接口会返回message参数: 需要把message转成POJO, 供后续使用.

    比如:
    protobuf的message

    message HelloRequest {
        string name = 1;
        int32 type = 2;
        string location = 3;
        bool flag = 4;
    }
    

    Java的POJO:

    @Getter
    @Setter
    @ToString
    public class HelloDTO {
        private String name;
        private Integer type;
        private String location;
        private Boolean flag;
        private String message;
    }
    

    POJO -> Message

    Hello.HelloRequest.Builder builder = Hello.HelloRequest.newBuilder();
    builder.setFlag(true);
    builder.setName("Name1");
    builder.setLocation("Location1");
    builder.setType(1);
    Hello.HelloRequest request = builder.build();
    

    Message -> POJO

    Hello.HelloRequest request;
    HelloDTO hello = new HelloDTO();
    hello.setFlag(request.getFlag());
    hello.setName(request.getName());
    hello.setLocation(request.getLocation());
    hello.setType(request.getType());
    

    可以想象, 在protobuf定义的message很多的情况下,这些代码写起来费时费力, 还容易遗漏,有什么好的方法可以解决这个问题呢?
    实际上POJO与PB Message之间的转换, 类似于POJO与Json之间的转换, 所以可以把上述过程简化:

    message -> POJO: 对于POJO中任一属性,只有message中也有时, 才取出来设置.

    /**
         * ProtoBuffer object to POJO
         */
        private static <T> T fromProtoBuffer(GeneratedMessageV3 pbObject, Class<T> modelClass) {
            T model = null;
    
            try {
                model = modelClass.newInstance();
                Field[] modelFields = modelClass.getDeclaredFields();
                if (modelFields != null && modelFields.length > 0) {
                    for (Field modelField : modelFields) {
                        String fieldName = modelField.getName();
                        String name = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
    
                        Class<?> fieldType = modelField.getType();
                        try {
                            Method pbGetMethod = pbObject.getClass().getMethod("get" + name);
                            Object value = pbGetMethod.invoke(pbObject);
    
                            Method modelSetMethod = modelClass.getMethod("set" + name, fieldType);
                            modelSetMethod.invoke(model, value);
                        } catch (NoSuchMethodException e) {
                            e.printStackTrace();
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            return model;
        }
    

    POJO -> message: 对于message中任一属性,只有POJO中也有时, 才取出来设置.

        /**
         * POJO -> ProtoBuffer object
         */
        private static <T> T toProtoBuffer(Object model, Class<T> pbClass) {
            if (!GeneratedMessageV3.class.isAssignableFrom(pbClass)) {
                throw new RuntimeException("Not ProtoBuffer message type");
            }
    
            T pbObject = null;
    
            try {
                Object pbBuilder = pbClass.getDeclaredMethod("newBuilder").invoke(null);
                Field[] pbFields = pbClass.getDeclaredFields();
                if (pbFields != null && pbFields.length > 0) {
                    for (Field pbField : pbFields) {
                        String fieldName = pbField.getName().substring(0, pbField.getName().length() - 1);
                        String name = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
                        Class<?> fieldType = pbField.getType();
                        if (pbField.getType() == Object.class) {
                            fieldType = String.class;
                        }
    
                        try {
                            Method modelGetMethod = model.getClass().getMethod("get" + name);
                            Object value = modelGetMethod.invoke(model);
                            if (value != null) {
                                Method pbBuilderSetMethod = pbBuilder.getClass().getMethod("set" + name, fieldType);
                                pbBuilderSetMethod.invoke(pbBuilder, value);
                            }
                        } catch (NoSuchMethodException e) {
                            e.printStackTrace();
                        }
                    }
                }
                pbObject = (T) pbBuilder.getClass().getDeclaredMethod("build").invoke(pbBuilder);
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            return pbObject;
        }
    

    以上代码仅为示例代码(demo), 实际使用时往往message和POJO分别都是嵌套的, 因此需要略有调整.

    相关文章

      网友评论

        本文标题:protobuf 与 Java 对象互转

        本文链接:https://www.haomeiwen.com/subject/etvibqtx.html