Protobuf 和 Java:将对象放入 oneof

rig*_*lla 10 java protocol-buffers

假设你有这个 protobuf 模型:

message ComplexKey {
    string name = 1;
    int32 domainId = 2;
}

message KeyMsg {
    oneof KeyMsgOneOf {
        string name = 1;
        ComplexKey complexName= 2;
    }
}
Run Code Online (Sandbox Code Playgroud)

和一个对象 obj,您知道它是字符串或 ComplexKey。

问题

如果不显式检查 obj 类类型,这是使用 protobuf Java API 构建新的 KeyMsg 实例并将 obj 放置在正确字段中的最有效方法?

更新:如果 protoc 生成一个辅助方法来完成我需要的事情,那就太好了。

UPDATE2:给出下面 Mark G. 的正确评论并假设所有字段的类型不同,到目前为止我找到的最佳解决方案是(简化版本):

     List<FieldDescriptor> lfd = oneOfFieldDescriptor.getFields();
     for (FieldDescriptor fieldDescriptor : lfd) {
           if (fieldDescriptor.getDefaultValue().getClass() == oVal.getClass()) {
              vmVal = ValueMsg.newBuilder().setField(fieldDescriptor, oVal).build();
              break;
           }
     }
Run Code Online (Sandbox Code Playgroud)

mre*_*rek 6

您可以使用开关盒:

  public Object demo() {
    KeyMsg keyMsg = KeyMsg.newBuilder().build();
    final KeyMsg.KeyMsgOneOfCase oneOfCase = keyMsg.getKeyMsgOneOfCase();

    switch (oneOfCase) {
      case NAME: return keyMsg.getName();
      case COMPLEX_NAME: return keyMsg.getComplexName();
      case KEY_MSG_ONE_OF_NOT_SET: return null;
    }
  }
Run Code Online (Sandbox Code Playgroud)


And*_*ner 2

我怀疑还有比使用更好的方法instanceof

KeyMsg.Builder builder = KeyMsg.newBuilder();
if (obj instanceof String) {
  builder.setName((String) obj);
} else if (obj instanceof ComplexKey) {
  builder.setComplexName((ComplexKey) obj);
} else {
  throw new AssertionError("Not a String or ComplexKey");
}
KeyMsg msg = builder.build();
Run Code Online (Sandbox Code Playgroud)

  • 我不认为*可以*有更好的方法,因为在一般情况下*库无法仅通过类型知道您的意思* - 因为 `string name = 1; 复杂密钥复杂名称= 2; 字符串地址=3;ComplexKey anotherName = 4;` 将与 `oneof` 一样有效 - 并且您可以在下一个构建中添加它;因此不存在只检查类型的 API。 (2认同)