Ok… awesome… I do have the .proto’s ahead of time, so I can have them compiled to the .desc files and store those.
Here’s my .proto file:
package com.lithum.pbnj;
import "google/protobuf/descriptor.proto";
option java_package = "com.lithium.pbnj";
extend google.protobuf.FieldOptions {
optional bool isPii = 50101;
}
message MessagePublish {
required string uuid = 1;
required int64 timestamp = 2;
required int64 message_uid = 3;
required string message_content = 4;
required int64 message_author_uid = 5;
optional string email = 6 [(isPii) = true];
}
I compiled this .proto file into a .desc file using the command you gave me. I’m now trying to parse a DynamicMessage from the .desc file. Here’s the code I have so far.
DescriptorProtos.FileDescriptorSet descriptorSet = DescriptorProtos.FileDescriptorSet.parseFrom(PBnJ.class.getResourceAsStream("/messages.desc"));
Descriptors.Descriptor desc = descriptorSet.getFile(0).getDescriptorForType();
Messages.MessagePublish event = Messages.MessagePublish.newBuilder()
.setUuid(UUID.randomUUID().toString())
.setTimestamp(System.currentTimeMillis())
.setEmail("he...@example.com")
.setMessageAuthorUid(1)
.setMessageContent("hello world!")
.setMessageUid(1)
.build();
DynamicMessage dynamicMessage = DynamicMessage.parseFrom(desc, event.toByteArray());
The final line in the above code is throwing the following exception:
Exception in thread "main" com.google.protobuf.InvalidProtocolBufferException: Protocol message end-group tag did not match expected tag.
at com.google.protobuf.InvalidProtocolBufferException.invalidEndTag(InvalidProtocolBufferException.java:94)
at com.google.protobuf.CodedInputStream.checkLastTagWas(CodedInputStream.java:174)
at com.google.protobuf.CodedInputStream.readMessage(CodedInputStream.java:478)
at com.google.protobuf.MessageReflection$BuilderAdapter.parseMessage(MessageReflection.java:482)
at com.google.protobuf.MessageReflection.mergeFieldFrom(MessageReflection.java:780)
at com.google.protobuf.AbstractMessage$Builder.mergeFrom(AbstractMessage.java:336)
at com.google.protobuf.AbstractMessage$Builder.mergeFrom(AbstractMessage.java:318)
at com.google.protobuf.AbstractMessage$Builder.mergeFrom(AbstractMessage.java:229)
at com.google.protobuf.AbstractMessageLite$Builder.mergeFrom(AbstractMessageLite.java:180)
at com.google.protobuf.AbstractMessage$Builder.mergeFrom(AbstractMessage.java:419)
at com.google.protobuf.AbstractMessage$Builder.mergeFrom(AbstractMessage.java:229)
at com.google.protobuf.AbstractMessageLite$Builder.mergeFrom(AbstractMessageLite.java:171)
at com.google.protobuf.AbstractMessage$Builder.mergeFrom(AbstractMessage.java:412)
at com.google.protobuf.DynamicMessage.parseFrom(DynamicMessage.java:119)
at com.lithium.pbnj.PBnJ.main(PBnJ.java:36)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
Ok… so I was finally able to parse a dynamic message and it looks good. It looks like it was just a user error on my part… after a little bit of digging around, I found the right APIs to call. Now my code looks like:
Descriptors.FileDescriptor fieldOptionsDesc = DescriptorProtos.FieldOptions.getDescriptor().getFile();
DescriptorProtos.FileDescriptorSet set = DescriptorProtos.FileDescriptorSet.parseFrom(
PBnJ.class.getResourceAsStream("/messages.desc"));
Descriptors.Descriptor md = Descriptors.FileDescriptor.buildFrom(set.getFile(0),
new Descriptors.FileDescriptor[]{fieldOptionsDesc}).findMessageTypeByName("MessagePublish");
Messages.MessagePublish event = Messages.MessagePublish.newBuilder()
.setUuid(UUID.randomUUID().toString())
.setTimestamp(System.currentTimeMillis())
.setEmail("he...@example.com")
.setMessageAuthorUid(1)
.setMessageContent("hello world!")
.setMessageUid(1)
.build();
DynamicMessage dynamicMessage = DynamicMessage.parseFrom(md, event.toByteArray());
// Parse worked!
for (Descriptors.FieldDescriptor fieldDescriptor : md.getFields()) {
Boolean extension = fieldDescriptor.getOptions().getExtension(Messages.isPii);
System.out.println(fieldDescriptor.getName() + " isPii = " + extension);
}
The output is:
uuid isPii = false
timestamp isPii = false
message_uid isPii = false
message_content isPii = false
message_author_uid isPii = false
email isPii = false
For some reason, this is incorrectly showing “isPii = false” for the email field when it should be “isPii = true” (as it is in the .proto file). Any thoughts on this?
Thanks again all!
> email to protobuf+unsubscribe@googlegroups.com.
Ok… I finally figured out the work around for this. I use a separate .proto file that contains my custom options.
package com.lithum.pbnj;
import "google/protobuf/descriptor.proto";
option java_package = "com.lithium.pbnj";
message LiOptions {
optional bool isPii = 1 [default = false];
optional bool isEmail = 2 [default = false];
optional bool isIpAddress = 3 [default = false];
}
extend google.protobuf.FieldOptions {
optional LiOptions li_opts = 50101;
}
Then I compile this .proto into a .java and can use it. When a message uses this extension, I can figure out which fields use my options, I use the following code:
Descriptors.FileDescriptor fieldOptionsDesc = DescriptorProtos.FieldOptions.getDescriptor().getFile();
Descriptors.FileDescriptor extensionsDesc = Extensions.getDescriptor().getFile();
Descriptors.FileDescriptor[] files = new Descriptors.FileDescriptor[]{fieldOptionsDesc, extensionsDesc};
DescriptorProtos.FileDescriptorSet set = DescriptorProtos.FileDescriptorSet.parseFrom(
PBnJ.class.getResourceAsStream("/messages.desc"));
DescriptorProtos.FileDescriptorProto messages = set.getFile(0);
Descriptors.FileDescriptor fileDesc = Descriptors.FileDescriptor.buildFrom(messages, files);
Descriptors.Descriptor md = fileDesc.findMessageTypeByName("MessagePublish");
Set<Descriptors.FieldDescriptor> piiFields = Sets.newHashSet();
for (Descriptors.FieldDescriptor fieldDescriptor : md.getFields()) {
DescriptorProtos.FieldOptions options = fieldDescriptor.getOptions();
UnknownFieldSet.Field field = options.getUnknownFields().asMap().get(Extensions.LI_OPTS_FIELD_NUMBER);
if (field != null) {
Extensions.LiOptions liOptions = Extensions.LiOptions.parseFrom(field.getLengthDelimitedList().get(0).toByteArray());
if (liOptions.getIsEmail() || liOptions.getIsIpAddress() || liOptions.getIsPii()) {
piiFields.add(fieldDescriptor);
System.out.println(fieldDescriptor.toProto());
}
}
}