rigazilla
rigazilla

Reputation: 179

Protobuf and Java: put object into oneof

Suppose you have this protobuf model:

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

message KeyMsg {
    oneof KeyMsgOneOf {
        string name = 1;
        ComplexKey complexName= 2;
    }
}

and an object obj, that you know is either a string or a ComplexKey.

Question

Whitout explicitly checking the obj class type, which is the most efficient way to build a new KeyMsg instance with the obj placed in the correct field using the protobuf Java API?

UPDATE: it would be great if protoc generates an helper method to do what I need.

UPDATE2: given the correct comment from Mark G. below and supposing that all fields differ in type, the best solution I've find so far is (simplified version):

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

Upvotes: 11

Views: 15718

Answers (2)

mrek
mrek

Reputation: 1888

You can use switch-case:

  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;
    }
  }

Upvotes: 8

Andy Turner
Andy Turner

Reputation: 140299

I doubt there is a better way than using 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();

Upvotes: 1

Related Questions