How to deal with unknown protobuf fields in Java?
Asked Answered
R

1

7

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.

Ryanryann answered 11/5, 2019 at 13:39 Comment(2)
Have you tested the behaviour when the user opens the data using an outdated .proto file? Is there a simple exception that you can catch and respond to in this case?Contemporize
if you generate java class using protoc it contains unknownFields field, it will be populated with tag number and value ( as new proto contains for example tag 4 which is not available in outdated proto file )Trinette
G
5

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.

Gorgias answered 11/2, 2020 at 12:28 Comment(1)
FieldDescriptor field =invbuilder.getDescriptorForType().findFieldByName("key_name"); This field object value is null. builder.setField(field, 100); So, setField throws ExceptionAshwin

© 2022 - 2024 — McMap. All rights reserved.