使用Gson使用默认值序列化protobuf

时间:2019-07-16 08:30:26

标签: java json serialization gson protocol-buffers

我正在尝试使用Gson库和ProtoTypeAdapter

将以Java类表示的protobuf消息序列化为JSON。
ProtoTypeAdapter adapter = ProtoTypeAdapter.newBuilder()
        .setFieldNameSerializationFormat(CaseFormat.LOWER_UNDERSCORE, CaseFormat.LOWER_UNDERSCORE)
        .build();
Gson gson = new GsonBuilder()
        .registerTypeAdapter(SomeAutogeneratedClass.class, adapter)
        .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
        .disableHtmlEscaping()
        .create();

suchMessage.getMyIntField()  // which is 0
String serialized = gson.toJson(suchMessage)

但是,似乎没有序列化0字段的默认值,例如int。 如何在JSON中包含具有默认值的那些字段?

2 个答案:

答案 0 :(得分:0)

我对this line进行了如下修改:

//        final Map<FieldDescriptor, Object> fields = src.getAllFields();  // original line

        // --- Include default value fields (See com.google.protobuf.util.JsonFormat) ---
        final Map<FieldDescriptor, Object> fields = new TreeMap<>(src.getAllFields());
        for (FieldDescriptor field : src.getDescriptorForType().getFields()) {
            if (field.isOptional()) {
                if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE
                        && !src.hasField(field)) {
                    continue;
                }
                Descriptors.OneofDescriptor oneof = field.getContainingOneof();
                if (oneof != null && !src.hasField(field)) {
                    continue;
                }
            }
            if (!fields.containsKey(field)) {
                fields.put(field, src.getField(field));
            }
        }
        // ------

答案 1 :(得分:0)

我创建了一个小脚本,该脚本使用反射通过将默认值更改为永远无法使用的内容来解决此问题。

public static void overrideDefaultValue(Descriptors.FieldDescriptor desc, Object newDefault) throws IllegalAccessException, NoSuchFieldException {
    Field f = Descriptors.FieldDescriptor.class.getDeclaredField("defaultValue");
    f.setAccessible(true);
    f.set(desc, newDefault);
}

比方说,您正在尝试序列化表示索引的值。那么-1是一个不可能的值。您可以像这样使用它:

overrideDefaultValue(MyMessage.getDescriptor().findFieldByName("my_field"), -1);