【问题标题】:Convert a protobuf to JSON using Jackson?使用 Jackson 将 protobuf 转换为 JSON?
【发布时间】:2019-01-06 09:32:56
【问题描述】:

使用 Jackson 的 ObjectMapper 将 protobuf 转换为 JSON 时出现以下错误:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: 
Direct self-reference leading to cycle (through reference chain:
MyObjectPb$MyObject["unknownFields"]->
com.google.protobuf.UnknownFieldSet["defaultInstanceForType"])

MyObjectPb 有以下字段:

protected com.google.protobuf.UnknownFieldSet unknownFields

在处理现有代码库时,我有以下限制:

  1. 我无法修改 MyObjectPb 的源代码,所以我无法在 MyObjectPb 中使用 Jackson 的忽略注解。
  2. 我也不能使用 Gson 的库来转换对象,因为代码库已经使用 Jackson 进行序列化。不建议添加新的依赖项。

如何告诉 Jackson 忽略(反)序列化 MyObjectPb 中的 UnknownFieldSet 对象?


我尝试了以下方法,但这些方法似乎无法解决问题:

a) 配置 ObjectMapper:

myObjectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
myObjectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);

b) 使用 Jackson Mixin:

@JsonIgnoreType
private abstract class UnknownFieldSetIgnoreMixIn {}

myObjectMapper.addMixIn(UnknownFieldSet.class, UnknownFieldSetIgnoreMixIn.class)

【问题讨论】:

  • mixin 是我的第一个猜测。您可能必须声明一个并行类以供 JSON 使用。 MapStruct 可以帮助在那里来回转换。
  • @chrylis 请问mixin实现是否合适或者我错过了什么?我会查找 MapStruct,非常感谢。

标签: java json jackson protocol-buffers


【解决方案1】:

我使用了JsonFormat类(com.googlecode.protobuf.format.JsonFormat)来转换protobuf:

new JsonFormat().printToString(myObject)

这对我来说非常完美。

【讨论】:

    【解决方案2】:

    包含已从 com.googlecode.protobuf.format.JsonFormat 更改 到 com.google.protobuf.util.JsonFormat

    因此,如果您的 protobuf 依赖项缺少 format 包,请尝试在 util 中查找 JsonFormat

    有了这个包含,你应该可以使用

    new JsonFormat().printToString(myObject)
    

    正如@amad-person 建议的那样。

    【讨论】:

      【解决方案3】:

      当前(2018 年 10 月)序列化 protobuf 的方法是按以下方式使用 com.google.protobuf.util.JsonFormat

      JsonFormat.printer().print(myMessageOrBuilder)
      

      我在我的 protobuf 对象之前使用了 @JsonSerialize(using = MyMessageSerializer.class) 注释并添加了这个类:

      public static class MyMessageSerializer extends JsonSerializer<Message> {
          @Override
          public void serialize(Message message, JsonGenerator gen, SerializerProvider serializers) throws IOException {
              gen.writeRawValue(JsonFormat.printer().print(message));
          }
      }
      

      这允许 new ObjectMapper().writeValueAsString(wrapperObject) 正确地将我的 protobuf 转换为 JSON。

      【讨论】:

      • gen.writeRawValue 如果 protobuf 对象只是 POJO 类中的一个成员
      • 在 sprinboot webflux 中,这个序列化选项/注释有效。唯一的问题是,每次 proto 对象重新生成后,我们都必须编辑生成的 java 代码。
      • 我试过了,但出现以下异常:No serializer found for class com.google.protobuf.UnknownFieldSet$Parser and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: ru.vtb.mmba.account.AccountProto$BankAccountInfo["unknownFields"]
      • 注解@JsonSerialize(using = ProtobufSerializer.class)好像没用。如果只是将JsonFormat.printer().print(accountInfo) 传递给objectMapper.writeValueAsString,那么它就可以工作。那么为什么@JsonSerialize(using 会被objectMapper.writeValueAsString 忽略呢?
      【解决方案4】:

      您应该使用 com.google.protobuf.util.JsonFormat 包中的以下类:

      JsonFormat.printer().print()
      

      【讨论】:

        【解决方案5】:

        我只是有这个问题,并使用下面的代码从 Message 对象创建 JSON:

        JsonFormat.printer().print(getMessageCockroachDB)
        

        【讨论】:

          【解决方案6】:

          这里有一个杰克逊的 protobuf 库:https://github.com/FasterXML/jackson-dataformats-binary

          虽然关于如何使用它的文档很少!有一些关于如何使用它进行读/写的示例:https://github.com/FasterXML/jackson-dataformats-binary/blob/2.14/protobuf/src/test/java/com/fasterxml/jackson/dataformat/protobuf/ReadSimpleTest.java#L66

          但尚不清楚这将如何放在 GRPC 应用程序中。

          【讨论】:

            猜你喜欢
            • 2015-06-03
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-03-25
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多