I'm using protocol buffers 2.5 with Java. I have a proto file that defines 
a custom option. Another proto file uses that custom option. If I persist 
the corresponding FileDescriptorProto's and then read them and convert them 
to FileDescriptors, the reference to the custom option is manifested as 
unknown field. How do I cause that custom option to be resolved correctly?

Here's the code. I have two .proto files. protobuf-options.proto looks like 
this:

package options;
import "google/protobuf/descriptor.proto";

option java_package = "com.example.proto";
option java_outer_classname = "Options";

extend google.protobuf.FieldOptions {
    optional bool scrub = 50000;}

The imported google/protobuf/descriptor.proto is exactly the 
descriptor.proto that ships with Protocol Buffers 2.5.

example.proto looks like this:

package example;
option java_package = "com.example.protos";
option java_outer_classname = "ExampleProtos";
option optimize_for = SPEED;
option java_generic_services = false;
import "protobuf-options.proto";

message M {
    optional int32 field1 = 1;
    optional string field2 = 2 [(options.scrub) = true];}

As you can see, field2 references the custom option defined by 
protobuf-options.proto.

The following code writes a binary-encoded version of all three protos to 
/tmp:

package com.example;
import com.google.protobuf.ByteString;import 
com.google.protobuf.DescriptorProtos.FileDescriptorProto;import 
com.google.protobuf.Descriptors.FileDescriptor;import 
com.example.protos.ExampleProtos;
import java.io.FileOutputStream;import java.io.OutputStream;
/**
 *
 */public class PersistFDs {
    public void persist(final FileDescriptor fileDescriptor) throws Exception {
        System.out.println("persisting "+fileDescriptor.getName());
        try (final OutputStream outputStream = new 
FileOutputStream("/tmp/"+fileDescriptor.getName())) {
            final FileDescriptorProto fileDescriptorProto = 
fileDescriptor.toProto();
            final ByteString byteString = fileDescriptorProto.toByteString();
            byteString.writeTo(outputStream);
        }
        for (final FileDescriptor dependency : 
fileDescriptor.getDependencies()) {
            persist(dependency);
        }
    }
    public static void main(String[] args) throws Exception {
        final PersistFDs self = new PersistFDs();
        self.persist(ExampleProtos.getDescriptor());
    }}

Finally, the following code loads those those protos from /tmp, converts 
them back into FileDescriptors, and then checks for the custom option on 
field2:

package com.example;
import com.google.protobuf.ByteString;import 
com.google.protobuf.DescriptorProtos.FileDescriptorProto;import 
com.google.protobuf.Descriptors.FieldDescriptor;import 
com.google.protobuf.Descriptors.FileDescriptor;import 
com.google.protobuf.UnknownFieldSet.Field;
import java.io.FileInputStream;import java.io.InputStream;
/**
 *
 */public class LoadFDs {
    public FileDescriptorProto loadProto(final String filePath) throws 
Exception {
        try (final InputStream inputStream = new FileInputStream(filePath)) {
            final ByteString byteString = ByteString.readFrom(inputStream);
            final FileDescriptorProto result = 
FileDescriptorProto.parseFrom(byteString);

            return result;
        }
    }

    public static void main(final String[] args) throws Exception {
        final LoadFDs self = new LoadFDs();

        final FileDescriptorProto descriptorFDProto = 
self.loadProto("/tmp/google/protobuf/descriptor.proto");
        final FileDescriptorProto optionsFDProto = 
self.loadProto("/tmp/protobuf-options.proto");
        final FileDescriptorProto fakeBoxcarFDProto = 
self.loadProto("/tmp/example.proto");

        final FileDescriptor fD = FileDescriptor.buildFrom(descriptorFDProto, 
new FileDescriptor[0]);
        final FileDescriptor optionsFD = 
FileDescriptor.buildFrom(optionsFDProto, new FileDescriptor[] { fD });
        final FileDescriptor fakeBoxcarFD = 
FileDescriptor.buildFrom(fakeBoxcarFDProto, new FileDescriptor[] { optionsFD });

        final FieldDescriptor optionsFieldDescriptor = 
optionsFD.findExtensionByName("scrub");
        if (optionsFieldDescriptor == null) {
            System.out.println("Did not find scrub's FieldDescriptor");
            System.exit(1);
        }
        final FieldDescriptor sFieldDescriptor = 
fakeBoxcarFD.findMessageTypeByName("M").findFieldByName("field2");
        System.out.println("unknown option fields 
"+sFieldDescriptor.getOptions().getUnknownFields());
        final boolean hasScrubOption = 
sFieldDescriptor.getOptions().hasField(optionsFieldDescriptor);
        System.out.println("hasScrubOption: "+hasScrubOption);

    }}

When I run LoadFDs, it fails with this exception:

unknown option fields 50000: 1

Exception in thread "main" java.lang.IllegalArgumentException: 
FieldDescriptor does not match message type. at 
com.google.protobuf.GeneratedMessage$ExtendableMessage.verifyContainingType(GeneratedMessage.java:812)
 
at 
com.google.protobuf.GeneratedMessage$ExtendableMessage.hasField(GeneratedMessage.java:761)
 
at com.example.LoadFDs.main(LoadFDs.java:42)

The options for FieldDescriptor for the s field ought to have a field for 
that custom option, but instead it has an unknown field. The field number 
and value on the unknown field are correct. It's just that the custom 
option is not getting resolved. How do I fix that?
Bill Smith
Austin, TX

-- 
You received this message because you are subscribed to the Google Groups 
"Protocol Buffers" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to protobuf+unsubscr...@googlegroups.com.
To post to this group, send email to protobuf@googlegroups.com.
Visit this group at https://groups.google.com/group/protobuf.
For more options, visit https://groups.google.com/d/optout.

Reply via email to