Protobuf构建含wrappers包装类型的DynamicMessage报错如何解决
问题原因
出现com.google.protobuf.InvalidProtocolBufferException: Invalid wrapper type: google.protobuf.StringValue报错的核心原因是:JsonFormat解析器默认没有注册Protobuf标准已知类型(Well-Known Types,包含wrappers.proto下的所有包装类型)的元信息。使用DynamicMessage动态构造消息时,解析器会将这些标准包装类型识别为普通自定义嵌套消息,触发类型校验失败。
另外给出的第一版proto示例存在语法错误,message定义缺少包裹字段的大括号,会直接导致proto编译失败,需要先修正。
解决方案
方案1:使用默认类型注册表(适用于protobuf-java 3.8及以上版本)
直接调用usingDefaultTypeRegistry()方法初始化解析器,会自动注册所有官方标准已知类型,不需要手动逐个添加包装类型,代码修改如下:
// 初始化带默认类型注册表的JSON解析器 JsonFormat.Parser parser = JsonFormat.parser().usingDefaultTypeRegistry(); DynamicMessage.Builder dynamicMessageBuilder = DynamicMessage.newBuilder(someDescriptor); parser.merge(stringPayload, dynamicMessageBuilder); byte[] blah = dynamicMessageBuilder.build().toByteArray();
方案2:手动注册包装类型描述符(适用于低版本protobuf-java)
如果使用的版本不支持默认注册表方法,可以手动将用到的包装类型描述符添加到自定义类型注册表中,protobuf-java依赖本身已经内置了所有标准类型的实现,不需要额外引入proto文件:
// 构建包含所需包装类型的注册表 TypeRegistry typeRegistry = TypeRegistry.newBuilder() .add(google.protobuf.StringValue.getDescriptor()) .add(google.protobuf.Int64Value.getDescriptor()) .add(google.protobuf.DoubleValue.getDescriptor()) .build(); // 用自定义注册表初始化解析器 JsonFormat.Parser parser = JsonFormat.parser().usingTypeRegistry(typeRegistry); DynamicMessage.Builder dynamicMessageBuilder = DynamicMessage.newBuilder(someDescriptor); parser.merge(stringPayload, dynamicMessageBuilder); byte[] blah = dynamicMessageBuilder.build().toByteArray();
注意事项
- 首先修正proto文件的语法错误,正确的定义格式如下:
import "google/protobuf/wrappers.proto"; message someMessage { .google.protobuf.StringValue someString = 1; .google.protobuf.Int64Value someInt = 2; .google.protobuf.DoubleValue someDouble = 3; }
- 传入的JSON payload必须符合包装类型的序列化规则,包装类型是Protobuf定义的标准消息,不能直接传基础类型值,需要嵌套
value字段,正确格式示例:
{ "someString": {"value": "测试文本"}, "someInt": {"value": 10086}, "someDouble": {"value": 9.9} }
内容的提问来源于stack exchange,提问作者Brian
相关产品推荐
相关产品推荐

