天道酬勤,学无止境

How to deal with unknown protobuf fields in Java?

I have a Java application that reads some protobuf data from another computer and can then modify some values and write it back. It is very likely that a user could read the data using an outdated .proto file, so there would be some fields it doesn't understand in this case. I would ultimately like to preserve the uknown data when writing back the changes made; however, I could settle for just detecting that there is unknown data (to prompt the user to upgrade his/her application). It is not clear to me how to deal with unknown fields in Java.

If it helps, I am using a version 2 .proto file because I need it to be compatible with nanopb on the remote computer.

This question gets me part of the way, but my question has nothing to do with JSON.

评论

First please pay attention when you say unknown fields. In protobuf you can have unknown fields by definition but on the other hand - and I suppose this is your case - you can have fields that you not having in your current proto file.

In both situation you can easily access the values. Let say you have a proto message named foo.

You have to access the descriptor and get the fields from there by name, and lastly get the values exemplified like below:

Builder builder = foo.toBuilder();
FieldDescriptor field = builder.getDescriptorForType().findFieldByName("whatever field");
Object obj = builder.getField(field);

// if your field is int32 cast to int
int value = (int) obj

If you wish to write the 'unknown' value you could proceed the other way around:

Builder builder = foo.toBuilder();
FieldDescriptor field = builder.getDescriptorForType().findFieldByName("whatever field");
builder.setField(field, 100); // 100 is an example int value
Foo foo = builder.build();

In case if you really want to insert proto defined unknown fields you have to do something like:

 UnknownFieldSet.Field seqField = UnknownFieldSet.Field
            .newBuilder()
            .addFixed32(100) // 100 is an example int value
            .build();

 UnknownFieldSet unkFieldSet = UnknownFieldSet
            .newBuilder()
            .addField(99, seqField) // 99 is a proto index number chosen by me
            .build();

 Foo message = foo.toBuilder().setUnknownFields(unkFieldSet).build();

Reading the defined unknown fields are again is done by the:

 foo.toBuilder().getUnknownFields()....

I hope this helps.

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 使用独立NDK工具链构建协议缓冲区(Building Protocol Buffers with Standalone NDK toolchain)
    问题 我无法使用使用$ NDK / build / tools / make-standalone-toolchain.sh脚本创建的独立NDK工具链为Android构建协议缓冲区。 我遇到的问题是这样的: libtool: link: g++ -Wall -Wwrite-strings -Woverloaded-virtual -Wno-sign-compare -O2 -g -DNDEBUG -o protoc main.o ./.libs/libprotobuf.a ./.libs/libprotoc.a /home/sizeak/AudioFingerprinting/ProtoBuf/jni/src/.libs/libprotobuf.a -lz -lc ./.libs/libprotoc.a(plugin.pb.o): In function `GoogleOnceInit': /home/sizeak/AudioFingerprinting/ProtoBuf/jni/src/./google/protobuf/stubs/once.h:115: undefined reference to `pthread_once' 这似乎意味着缺少pthreads库,但是sysroot是由ndk脚本创建的,因此应该包含所有内容,对吗? 我在某处读到
  • Java:JSON-> Protobuf和反向转换(Java: JSON -> Protobuf & back conversion)
    问题 我有一个现有系统,该系统在GUI和服务器之间使用基于Protobuf的通信协议。 现在,我想添加一些持久性,但是目前protobuf消息已直接转换为第三方自定义对象。 有没有一种方法可以将原始消息转换为json ,然后可以将其持久化到数据库中。 注意:我不太喜欢将二进制protobuf写入数据库的想法,因为它有一天可能变得无法与较新版本向后兼容并以这种方式破坏系统。 回答1 如对类似问题的回答中所述,自v3.1.0起,这是ProtocolBuffers的受支持功能。 对于Java,请包括扩展模块com.google.protobuf:protobuf-java-util,并使用JsonFormat,如下所示: JsonFormat.parser().ignoringUnknownFields().merge(json, yourObjectBuilder); YourObject value = yourObjectBuilder.build(); 回答2 我们目前正在使用protobuf-java-format将Protobuf消息( Message任何子类)转换为JSON格式,以通过我们的Web API发送。 只需做: JsonFormat.printToString(protoMessage) 回答3 我不太喜欢将二进制protobuf写入数据库的想法
  • Python中未知类型Protobuf消息的访问字段(Accessing field of Protobuf message of unknown type in Python)
    问题 假设我有 2 个 Protobuf 消息,A 和 B。它们的整体结构相似,但不完全相同。 所以我们将共享的内容移到了一个单独的消息中,我们称为 Common。 这很好用。 但是,我现在面临以下问题:存在一种特殊情况,我必须处理序列化消息,但我不知道它是类型 A 还是类型 B 的消息。我在 C++ 中有一个可行的解决方案(如图所示)下面),但我没能找到在 Python 中做同样事情的方法。 例子: // file: Common.proto // contains some kind of shared struct that is used by all messages: message Common { ... } // file: A.proto import "Common.proto"; message A { required int32 FormatVersion = 1; optional bool SomeFlag [default = true] = 2; optional Common CommonSettings = 3; ... A-specific Fields ... } // file: B.proto import "Common.proto"; message B { required int32 FormatVersion = 1
  • 如何在协议缓冲区中设计未来的附加枚举值?(How to design for a future additional enum value in protocol buffers?)
    问题 协议缓冲区的一个吸引人的特性是它允许您扩展消息定义而不会破坏使用旧定义的代码。 在根据文档的枚举的情况下: 具有枚举类型的字段只能将一组指定的常量中的一个作为其值(如果您尝试提供不同的值,解析器会将其视为未知字段) 因此,如果您扩展枚举并使用新值,那么旧代码中具有该类型的字段将是未定义的或具有其默认值(如果有)。 知道将来枚举可能会添加额外的值,处理这个问题的好策略是什么? 想到的一种方法是定义枚举的“未定义”成员并将其设为默认值,然后旧代码将知道它已发送了无法解释的内容。 这是明智的,有没有更好的方法来处理这种情况? 回答1 是的,最好的方法是使枚举中的第一个值类似于UNKNOWN = 0 。 然后旧程序读取带有他们无法识别的枚举值的 protobuf 会将其视为UNKNOWN并希望他们可以合理地处理它,例如通过跳过该元素。 如果您想这样做,您还需要将 enum 设为optional not required 。 required ,一般来说,意味着“我宁愿程序只是中止而不是处理它不理解的东西。” 请注意,它必须是 proto 源中声明的第一个值- 只是零值不会使其成为默认值。
  • protocal buffers 官方文档学习
    protocal buffers 官方文档学习 文章目录 protocal buffers 官方文档学习1.What are protocol buffers?2.选择你喜欢的语言3.怎么开始,步骤3.1下载和安装protocal buffer 编译器3.2阅读入门指南3.2.1 开发者指南3.2.1.1 怎么开始?3.2.1.2为什么不使用xml?3.2.1.3介绍一下protobuf3 3.2.2 proto3语言3.2.2.1 定义一个消息类型3.2.2.2 字段值类型3.2.2.3枚举3.2.2.4 使用消息类型3.2.2.5嵌套类型3.2.2.6 更新一个消息时怎么办3.2.2.7 未知的字段3.2.2.8 any 类型3.2.2.9Oneof3.2.2.11定义服务3.2.2.12可选项 3.2.3编码风格指南3.2.3.1标准文件格式3.2.3.2 消息和字段名称3.2.3.4 重复字段3.2.3.5 枚举3.2.3.4 重复字段3.2.3.5 枚举 前言:最近在做一个项目,负责通讯这块。采用技术是netty+protobuf 在安卓端和c#端进行通信。项目快差不多了,做一下沉淀,翻译一下protbuf文档,和自己的项目工程实践。工程实践代码可以看我的另一篇博文,是接着写的。 1.What are protocol buffers? protocal
  • gRPC快速入门(一)——Protobuf简介
    gRPC快速入门(一)——Protobuf简介 一、Protobuf简介 1、Protobuf简介 Protobuf即Protocol Buffers,是Google公司开发的一种跨语言和平台的序列化数据结构的方式,是一个灵活的、高效的用于序列化数据的协议。与XML和JSON格式相比,protobuf更小、更快、更便捷。protobuf是跨语言的,并且自带一个编译器(protoc),只需要用protoc进行编译,就可以编译成Java、Python、C++、C#、Go等多种语言代码,然后可以直接使用,不需要再写其它代码,自带有解析的代码。只需要将要被序列化的结构化数据定义一次(在.proto文件定义),便可以使用特别生成的源代码(使用protobuf提供的生成工具)轻松的使用不同的数据流完成对结构数据的读写操作。甚至可以更新.proto文件中对数据结构的定义而不会破坏依赖旧格式编译出来的程序。GitHub地址:https://github.com/protocolbuffers/protobuf不同语言源码版本下载地址:https://github.com/protocolbuffers/protobuf/releases/latest 2、Protobuf的优缺点 Protobuf的优点如下:A、性能号,效率高序列化后字节占用空间比XML少3-10倍,序列化的时间效率比XML快20
  • 处理原型缓冲区中的空值(Handling null values in protobuffers)
    问题 我正在研究从数据库中获取数据并构造probbuff消息的东西。 考虑到可以从数据库中为某些字段获取空值的可能性,在尝试构造probbuff消息时,我将获得Null-pointer异常。 从线程http://code.google.com/p/protobuf/issues/detail?id=57知道原型中不支持null,我想知道是否唯一处理NPE抛出的其他方法是将手动检查插入到与原型相对应的java文件中,如下所示! message ProtoPerson{ optional string firstName = 1; optional string lastName = 2; optional string address1 = 3; } ProtoPerson.Builder builder = ProtoPerson.Builder.newBuilder(); if (p.getFirstName() != null) builder.setFirstName(p.getFirstName()); if (p.getLastName() != null) builder.setLastName(p.getLastName()); if (p.getAddress1() != null) builder.setAddress1(p.getAddress1());
  • Accessing field of Protobuf message of unknown type in Python
    Let's say I have 2 Protobuf-Messages, A and B. Their overall structure is similar, but not identical. So we moved the shared stuff out into a separate message we called Common. This works beautifully. However, I'm now facing the following problem: A special case exists where I have to process a serialized message, but I don't know whether it's a message of type A or type B. I have a working solution in C++ (shown below), but I failed to find a way to do the same thing in Python. Example: // file: Common.proto // contains some kind of shared struct that is used by all messages: message Common {
  • What's the preferred way to encode a “nullable” field in protobuf 2?
    I am defining a ProtoBuf message where I want to have a "nullable" field -- i.e., I want to distinguish between the field having a value and not having a value. As a concrete example, let's say I have "x" and "y" fields to record the coordinates of some object. But in some cases, the coordinates are not known. The following definition will not work, because if x or y are unspecified, then they default to zero (which is a valid value): message MyObject { optional float x = 1; optional float y = 2; } One option would be to add a boolean field recording whether the corresponding field's value is
  • 在导入的 .proto 文件中扩展 protobuf.FieldOptions(Extending protobuf.FieldOptions in imported .proto file)
    问题 我正在尝试在 google 协议缓冲区中定义我的自定义字段选项。 如果我创建这样的文件,一切正常: import "google/protobuf/descriptor.proto"; package tutorial; extend google.protobuf.FieldOptions { optional int32 myopt = 70000; } message Persona { required string name = 1 [(myopt)=5]; } 但是,如果我尝试将“myopt”定义移动到另一个文件,编译将失败: myext.proto: package myext; import "google/protobuf/descriptor.proto"; extend google.protobuf.FieldOptions { optional int32 myopt = 70000; } 地址簿.proto: import "google/protobuf/descriptor.proto"; import "myext.proto"; package tutorial; message Persona { required string name = 1 [(myopt)=5]; } 汇编: $ protoc --cpp_out=. -I/usr
  • 为什么 parseFrom() 函数在 java socket 中使用 protobuf 挂起?(Why did parseFrom() function hang using protobuf in java socket?)
    问题 我只想使用 protobuf 和 java 创建回声服务器/客户端。 我用 protobuf-java-2.4.1 和 jdk1.7 进行了测试。 我写了如下的回声服务器代码 // create server socket and accept for client connection. // ... link = servSock.accept(); Person person = Person.parseFrom(link.getInputStream()); // blocking position person.writeTo(link.getOutputStream()); 我认为没有必要注意Person.proto。 客户端代码仅使用套接字输入流发送 Person 对象并接收 echo Person 对象。 // socket connect code was omitted. Person person = Person.newBuilder().setId(1).setName("zotiger").build(); person.writeTo(echoSocket.getOutputStream()); person = Person.parseFrom(echoSocket.getInputStream()); 但是当服务器和客户端都运行时,服务器在
  • Protobuf-net序列化枚举值超出范围的枚举(Protobuf-net serialize enum with value out of range)
    问题 C#允许将任何整数值分配给枚举。 当我尝试使用值超出范围的枚举字段(通过protobuf-net)序列化对象时,它将引发异常:没有线值映射到枚举PersonLevel。 我的枚举PersonLevel没有Flags属性。 [ProtoContract(ImplicitFields = ImplicitFields.AllFields)] public enum PersonLevel { Unknown = 1 } [ProtoContract(ImplicitFields = ImplicitFields.AllFields)] public class Person { ... public PersonLevel PersonLevel { get; set; } ... } var ms = new MemoryStream(); var person = new Person { ... PersonLevel = (PersonLevel) 500 ... }; Serializer.Serialize(ms, person); //No wire-value is mapped to the enum PersonLevel 是否有任何设施可以在不更改业务对象的情况下进行操作(可能是任何protobuf属性)? 回答1 有几种方法可以简化规则;
  • 【Protobuf协议】002-标准类型、默认值、枚举、使用费其他消息类型
    目录 三、标准类型 四、默认值 五、枚举 1、简单使用 2、别名 3、预留值 六、使用其他消息类型 1、简单例子 2、导入定义* 3、使用proto2消息类型 三、标准类型 其他语言见官方文档:https://developers.google.com/protocol-buffers/docs/javatutorial#scalar .proto TypeNotesJava Typedouble doublefloat floatint32使用可变长编码,编码负数的效率很低——如果你的字段可能有负数,使用sint32代替intint64使用可变长编码,编码负数的效率很低——如果你的字段可能有负数,使用sint64代替longuint32使用可变长度编码int[1]uint64使用可变长度编码long[1]sint32使用可变长编码,带符号的int值。它们比普通int32编码负数更有效intsint64使用可变长编码,带符号的int值。它们比普通int64编码负数更有效longfixed32总是4个字节,如果值经常大于2的28次方,则比uint32更有效int[1]fixed64总是8个字节,如果值经常大于2的56次方,则比uint64更有效long[1]sfixed32总是4个字节intsfixed64总是8个字节longbool
  • linux 环境下python3 对google 的 protobuf 安装和使用 详解
    1.安装 a>在线安装 安装protobuf环境: sudo snap install protobuf --classic 安装protobuf python库:pip3 install protobuf b>源码安装 下载源代码 安装protoc 解压:protoc-3.5.0-osx-x86_64.zip 将解压出的:protoc-3.5.0-osx-x86_64/bin/protoc至于系统路径中 输入:protoc --version 检查是否安装成功 安装Python扩展,protobuf 解压:protobuf-python-3.5.0.zip 进入目录:protobuf-3.5.0/python 首先更新:setuptools 和 pip, 执行命令:pip3 install -U setuptools pip 避免出现错误:AttributeError: '_NamespacePath' object has no attribute 'sort' 我的pip和setuptools版本分别是:pip: 10.0.0.dev0,setuptools: 36.7.2 然后依次执行: python3 setup.py build python3 setup.py test python3 setup.py install 检查是否安装成功 Python 3.6.3
  • Are there some better ways to address warnings when compiling protocol buffer generated source file?
    For a simple proto file: message Person { required int32 id = 1; required string name = 2; optional string email = 3; } It's been compiled by protoc.exe and the results are used in an also simple test project, which basically does nothing but including the protoc generated files. I'm using the msvc10 to build the test project (x64), then it gave me a lot of warning: Warning 1 warning C4244: 'return' : conversion from '__int64' to 'int', possible loss of data D:\Work\protobuf-trunk\src\google\protobuf\descriptor.h 1441 1 testProtobuf ... Warning 11 warning C4267: 'argument' : conversion from
  • protobuf详细介绍和使用
    一、protobuf初识 (一)protocol buffers 是什么? protocol buffers 是一种灵活,高效,自动化机制的结构数据序列化方法-可类比 XML,但是比 XML 更小、更快、更为简单。你可以定义数据的结构,然后使用特殊生成的源代码轻松的在各种数据流中使用各种语言进行编写和读取结构数据。你甚至可以更新数据结构,而不破坏根据旧数据结构编译而成并且已部署的程序。 (二)它是如何工作的? 你可以通过在 .proto 文件中定义 protocol buffer message 类型,来指定你想如何对序列化信息进行结构化。每一个 protocol buffer message 是一个信息的小逻辑记录,包含了一系列的 name-value 对。这里有一个非常基础的 .proto 文件样例,它定义了一个包含 "person" 相关信息的 message: message Person { required string name = 1; required int32 id = 2; optional string email = 3; ​ enum PhoneType { MOBILE = 0; HOME = 1; WORK = 2; } ​ message PhoneNumber { required string number = 1; optional
  • Protobuf:set_allocated_ *会删除分配的对象吗?(Protobuf: Will set_allocated_* delete the allocated object?)
    问题 我有这个小的protobuf代码(简化了,只包含必要的内容): message ParamsMessage { required int32 temperature = 1; } message MasterMessage { enum Type { GETPARAMS = 1; SENDPARAMS = 2;} required Type type = 1; optional ParamsMessage paramsMessage = 2; } 现在,我通过以下方式创建MasterMessage: ParamsMessage * params = new ParamsMessage(); params->set_temperature(22); MasterMessage master; master.set_type(MasterMessage::SENDPARAMS); master.set_allocated_paramsmessage(params); 问题是:我是否必须(在处理完消息后)删除params消息,还是protobuf会为我删除它? 我在文档中找不到任何内容。 回答1 自问了问题以来,我一直在寻找答案。 也许有人也对答案感兴趣。 从这里:https://developers.google.com/protocol-buffers/docs
  • google protobuf最大大小(google protobuf maximum size)
    问题 我的protobuf讯息中有一些重复的内容。 在运行时,消息的长度可以是任意长度-我看到已经像这样问了一些问题-[1]:最大序列化Protobuf消息大小 我在这里有一个稍微不同的问题。 如果我的JMS(Java消息服务)提供程序(在这种情况下,是我的weblogic或tibco jms服务器)对最大消息大小没有任何大小限制,那么协议缓冲区编译器会根本抱怨最大消息大小吗? 在大尺寸(约10MB左右)下,编码/解码的性能是否会受到严重影响? 回答1 10MB正在推动它,但您可能会没事的。 Protobuf的硬限制为2GB,因为许多实现使用32位带符号算术。 出于安全原因,许多实施方式(尤其是Google提供的实施方式)默认都限制大小为64MB,不过您可以根据需要手动增加此限制。 该实现本身不会“放慢”大消息本身,但是问题是,在开始使用任何内容之前,必须始终一次解析整个消息。 这意味着整个消息必须适合RAM(请记住,解析内存中的消息对象比原始序列化消息大得多),即使您只关心一个字段,也必须等待整个过程完成。解析。 通常,根据经验,我建议尝试将自己限制为1MB。 除此之外,考虑将消息拆分为多个可以独立解析的块。 但是,每个应用程序(对于某些应用程序来说10MB都不是什么大问题,对于其他应用程序来说1MB已经太大了)。 您必须分析自己的应用程序才能找到。 实际上
  • Using Protobuf-net, I suddenly got an exception about an unknown wire-type
    (this is a re-post of a question that I saw in my RSS, but which was deleted by the OP. I've re-added it because I've seen this question asked several times in different places; wiki for "good form") Suddenly, I receive a ProtoException when deserializing and the message is: unknown wire-type 6 What is a wire-type? What are the different wire-type values and their description? I suspect a field is causing the problem, how to debug this?
  • 编译协议缓冲区生成的源文件时,是否有更好的方法来解决警告?(Are there some better ways to address warnings when compiling protocol buffer generated source file?)
    问题 对于一个简单的 proto 文件: message Person { required int32 id = 1; required string name = 2; optional string email = 3; } 它由 protoc.exe 编译,结果用于一个同样简单的测试项目,该项目基本上只包括 protoc 生成的文件。 我正在使用 msvc10 来构建测试项目 (x64),然后它给了我很多警告: Warning 1 warning C4244: 'return' : conversion from '__int64' to 'int', possible loss of data D:\Work\protobuf-trunk\src\google\protobuf\descriptor.h 1441 1 testProtobuf ... Warning 11 warning C4267: 'argument' : conversion from 'size_t' to 'int', possible loss of data D:\Work\protobuf-trunk\src\google\protobuf\unknown_field_set.h 142 1 testProtobuf Warning 12 warning C4267: 'return'