【发布时间】:2017-03-07 15:29:20
【问题描述】:
我在 Java 中使用协议缓冲区 2.5。我有一个定义自定义选项的原型文件。另一个 proto 文件使用该自定义选项。如果我持久化相应的FileDescriptorProto,然后读取它们并将它们转换为FileDescriptors,则对自定义选项的引用表现为未知字段。如何正确解决该自定义选项?
这是代码。我有两个 .proto 文件。 protobuf-options.proto 看起来像这样:
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;
}
导入的google/protobuf/descriptor.proto 正是Protocol Buffers 2.5 附带的descriptor.proto。
example.proto 看起来像这样:
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];
}
如您所见,field2 引用了protobuf-options.proto 定义的自定义选项。
以下代码将所有三个原型的二进制编码版本写入/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());
}
}
最后,以下代码从/tmp 加载那些原型,将它们转换回FileDescriptors,然后检查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);
}
}
当我运行LoadFDs 时,它失败并出现以下异常:
未知选项字段 50000: 1
线程“main”java.lang.IllegalArgumentException 中的异常:FieldDescriptor 与消息类型不匹配。 在 com.google.protobuf.GeneratedMessage$ExtendableMessage.verifyContainingType(GeneratedMessage.java:812) 在 com.google.protobuf.GeneratedMessage$ExtendableMessage.hasField(GeneratedMessage.java:761) 在 com.example.LoadFDs.main(LoadFDs.java:42)
s 字段的 FieldDescriptor 选项应该有一个用于该自定义选项的字段,但它有一个未知字段。未知字段上的字段编号和值是正确的。只是自定义选项没有得到解决。我该如何解决?
【问题讨论】:
-
遇到同样的事情 - 你有没有想过@user100464
标签: java protocol-buffers