Thomas Ny
Thomas Ny

Reputation: 92

How Can I Set a subclass field in Protocol Buffer, from Java Code?

I Have an Animal A Cat and Dog messages, but i don't know how to set cat's declawed, or dog's bones_buried field, if I create an object. I want to create a Cat, and create an animal object from it.

message Animal {
extensions 100 to max;
enum Type {
    Cat = 1;
    Dog = 2;
}
    required Type type = 1;
}


message Cat {
    extend Animal {
        required Cat animal = 100;
    }
    optional bool declawed = 1;
}
message Dog {
    extend Animal {
        required Dog animal = 101;
    }
    optional uint32 bones_buried = 1;
}

my Test Class:

public class Test {
public static void main(String[] args) {
    Animal.Builder animal = Animal.newBuilder().setType(Animal.Type.Cat);
    Cat c = animal.getExtension(Cat.animal);        

    Cat cat = Cat.newBuilder().setDeclawed(true).build();

    // animal = cat! 
    Animal a = animal.build();      

}
}

Upvotes: 0

Views: 168

Answers (1)

Kenton Varda
Kenton Varda

Reputation: 45181

Careful! Protobuf extensions are not subclasses. They can sometimes be used as a substitute for inheritance, but they work very differently from inheritance. For example, your Animal type can actually have both a Cat and a Dog extension at the same time.

Extensions actually behave like fields. Each time you extend Animal, you are essentially adding new fields to the Animal message. In other words, your proto is actually equivalent to this:

message Animal {
  enum Type {
    Cat = 1;
    Dog = 2;
  }
  required Type type = 1;
  optional Cat cat = 100;
  optional Dog dog = 101;
}

message Cat {
  optional bool declawed = 1;
}
message Dog {
  optional uint32 bones_buried = 1;
}

The only difference is that extensions can be declared outside of the message that they are extending.

In retrospect, I should have used a different word than "extend" to avoid confusion with inheritance.

Since extensions are just fields, they have accessors equivalent to field accessors. Here's how your code should be written:

Animal animal = Animal.newBuilder()
    .setType(Animal.Type.Cat);
    .setExtension(Cat.animal,
        Cat.newBuilder().setDeclawed(true))
    .build();

By the way, in your example you declare your extensions required. This is actually not allowed -- extensions can never be required, because extensions by their nature are inherently optional. If required extensions were actually allowed, then your proto would actually be declaring that every Animal had to have both a Cat and a Dog extension.

Upvotes: 1

Related Questions