如何转换Json至Protobuf?

时间:2016-07-15 23:17:18

标签: java json protocol-buffers

我是使用protobuf的新手,并且想知道是否有一种简单的方法可以将Java中的json流/字符串转换为protobuf流/字符串?

例如,

protoString = convertToProto(jsonString)

我有一个json字符串,我想解析为protobuf消息。所以,我想首先将json字符串转换为protobuf,然后在其上调用Message.parseFrom()

提前感谢您的帮助!

4 个答案:

答案 0 :(得分:18)

使用proto3,您可以使用JsonFormat执行此操作。它直接从JSON表示解析,因此不需要单独调用MyMessage.parseFrom(...)。这样的事情应该有效:

JsonFormat.parser().merge(json_string, builder);

答案 1 :(得分:1)

//You can use this for converting your input json to a Struct / any other Protobuf Class    

import com.google.protobuf.Struct.Builder;
import com.google.protobuf.Struct;
import com.google.protobuf.util.JsonFormat;
import org.json.JSONObject;

JSONObject parameters = new JSONObject();

Builder structBuilder = Struct.newBuilder();
JsonFormat.parser().merge(parameters.toString(), structBuilder);

// Now use the structBuilder to pass below (I used it for Dialog Flow V2 Context Management)

答案 2 :(得分:0)

在线服务: https://json-to-proto.github.io/

<块引用>

此工具可立即将 JSON 转换为 Protobuf。在左侧粘贴一个 JSON 结构,右侧将生成等效的 Protobuf,您可以将其粘贴到您的程序中。脚本必须做出一些假设,因此请仔细检查输出!

答案 3 :(得分:0)

由于有人询问在遵循 Adam 的建议时是否会收到异常“com.google.protobuf.InvalidProtocolBufferException: JsonObject”——我遇到了同样的问题。原来这是由于 google protobuf 时间戳。它们被序列化为包含两个字段“seconds”和“nanos”的对象,因为这不是生产代码,我只是通过使用 jackson 解析 JSON、递归遍历 JSON 对象并更改每个时间戳来解决这个问题对象转换为按照 RFC 3339 格式化的字符串,然后我将其序列化并使用 Adam 所示的 protobuf JSON 解析器。这解决了这个问题。这是我写的一些一次性代码(在我的例子中所有时间戳字段都包含“时间戳”这个词,这可能更健壮,但我不在乎):

public Map<String, Object> fixJsonTimestamps(Map<String, Object> inMap) {
    Map<String, Object> outMap = new HashMap<>();
    for(String key : inMap.keySet()) {
        Object val = inMap.get(key);
        if(val instanceof Map) {
            Map<String, Object> valMap = (Map<String, Object>)val;
            if(key.toLowerCase().contains("timestamp") && 
                    valMap.containsKey("seconds") && valMap.containsKey("nanos")) {
                if(valMap.get("seconds") != null) {
                    ZonedDateTime d = ZonedDateTime.ofInstant(Instant.ofEpochSecond((int)valMap.get("seconds")).plusNanos((int)valMap.get("nanos")),
                            ZoneId.of("UTC"));
                    val = d.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"));
                }
                
            } else {
                val = fixJsonTimestamps(valMap);
            }
        } else if(val instanceof List && ((List) val).size() > 0 && 
                ((List) val).get(0) instanceof Map) {
            List<Map<String, Object>> outputList = new ArrayList<>();
            for(Map item : (List<Map>)val) {
                outputList.add(fixJsonTimestamps(item));
            }
            val = outputList;
        }
        outMap.put(key, val);
    }
    return outMap;
}

不是最理想的解决方案,但它适用于我正在做的事情,我想我看到有人推荐使用不同的时间戳类。