如何在Java代码中设置协议缓冲区中的子类字段?

时间:2013-12-11 11:31:01

标签: java serialization protocol-buffers

我有动物猫和狗的消息,但是如果我创建一个对象,我不知道如何设置猫的声明或狗的bones_buried字段。 我想创建一个Cat,并从中创建一个动物对象。

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

我的测试类:

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();      

}
}

1 个答案:

答案 0 :(得分:1)

小心! Protobuf扩展是不是子类。它们有时可以用作继承的替代品,但它们与继承的工作方式完全不同。例如,您的Animal类型实际上可以同时 一个Cat 一个Dog扩展名。

扩展实际上表现得像字段一样。每次extend Animal时,您实际上都会向Animal消息添加新字段。换句话说,你的proto实际上相当于:

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

唯一的区别是扩展可以在它们正在扩展的消息之外声明。

回想起来,我应该使用与“扩展”不同的词来避免与继承混淆。

由于扩展只是字段,因此它们具有与字段访问器等效的访问器。以下是您的代码编写方式:

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

顺便说一下,在您的示例中,您声明了扩展程序required。实际上这是不允许的 - 永远不需要扩展,因为扩展本质上是可选的。如果实际允许所需的扩展,那么您的proto实际上会声明每个Animal必须 CatDog扩展名。