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.

bummi
  • 27,123
  • 14
  • 62
  • 101
Mike Foss
  • 311
  • 2
  • 6
  • 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? – Richard Neish May 13 '19 at 08:14
  • 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 ) – hi_my_name_is May 21 '19 at 05:28

1 Answers1

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.

Antal Attila
  • 588
  • 6
  • 18
  • `FieldDescriptor field =invbuilder.getDescriptorForType().findFieldByName("key_name");` This field object value is null. `builder.setField(field, 100); ` So, setField throws Exception – Esann May 20 '23 at 07:28