Noel Yap
Noel Yap

Reputation: 19778

How to get value of protobuf custom option in Java?

Background: I'm writing a protoc plugin.

The custom protobuf option is implemented with the following:

syntax = "proto3";

package com.example.proto.options;

import "google/protobuf/descriptor.proto";

option java_multiple_files = true;
option java_outer_classname = "ServerOptionsProto";
option java_package = "com.example.proto.options";

extend google.protobuf.FileOptions {
    ServerOptions server = 50621;
}

message ServerOptions {
    // Java classname
    string name = 1;
}

The following is an example usage:

syntax = "proto3";

package com.example.testdata;

import "com/example/proto/options/server.proto";

option java_multiple_files = true;
option java_package = "com.example.testdata.protogen";
option java_outer_classname = "TestDataProto";

option (com.example.proto.options.server).name = "TestData";

Trying to follow https://developers.google.com/protocol-buffers/docs/proto#options, the following (in Groovy) doesn't work:

request.getProtoFileList().stream().filter { proto ->
  proto.serviceCount > 0
}.flatMap { proto ->
  serverName = proto.getDescriptor().getOptions()?.getExtension(com.example.proto.options.ServerOptionsProto.server)?.name
}

What's the right way in Java to access the value of the custom option?

Upvotes: 3

Views: 5193

Answers (3)

Marco
Marco

Reputation: 491

For those that need to do it in Java: as mentioned by Noel, to refer to the a given custom option in your java source code, use java_package + java_outer_classname values that you have defined on top of your proto file.

Concrete example:

syntax = "proto3";

import "google/protobuf/descriptor.proto";

option java_multiple_files = true;
option java_package = "com.marco.grpc.server.v1";
option java_outer_classname = "MyGrpcServer";

extend google.protobuf.FieldOptions {
  bool encrypt = 50001;
}

Then in the source code, with the following code you can retrieve all the names of the fields that have a given option, in this case the custom encrypt option:

myProtoMessage.getDescriptorForType().getFields()
        .stream()
        .filter(field -> field.getOptions().getExtension(com.marco.grpc.server.v1.MyGrpcServer.encrypt))
        .map(FieldDescriptor::getName)
        .collect(Collectors.toList());

Upvotes: 0

Noel Yap
Noel Yap

Reputation: 19778

The java_package and java_outer_classname options need to be used:

serverName = proto.getOptions()?.getExtension(com.example.proto.options.ServerOptionsProto.server)?.name

Also, since this is processed by a protoc plugin, the extension needs to be registered as per Extensions:

final registry = ExtensionRegistry.newInstance();
registry.add(ServerOptionsProto.server)
final request = PluginProtos.CodeGeneratorRequest.parseFrom(input, registry)

Upvotes: 4

Adam Cozzette
Adam Cozzette

Reputation: 1476

I believe the problem is that your option is a file-level one, but you are trying to access it as if it were a message-level option. Instead of proto.getDescriptor().getOptions(), try proto.getDescriptor().getFile().getOptions().

Upvotes: -1

Related Questions