最初的回答:使用鉴别器多态性来解决序列化协议的问题。传统的面向对象继承是一种带有一些非常不好特性的形式。在像 OpenAPI 这样的新协议中,这个概念更加干净。
让我解释一下 proto3 是如何工作的。
首先,您需要声明您的多态类型。假设我们采用经典的动物物种问题,不同的物种具有不同的属性。我们首先需要定义一个所有动物都将识别其物种的根本类型。然后我们声明一个猫和狗的消息,这些消息扩展了基本类型。请注意,在所有三个消息中都投影了鉴别器“物种”。
message BaseAnimal {
string species = 1;
}
message Cat {
string species = 1;
string coloring = 10;
}
message Dog {
string species = 1;
int64 weight = 10;
}
这里有一个简单的Java测试,用来演示实践中的工作原理。
最初的回答:Original Answer
ByteArrayOutputStream os = new ByteArrayOutputStream(1024);
Cat cat = Cat.newBuilder().setSpecies("CAT").setColoring("spotted")
.build();
cat.writeTo(os);
byte[] catSerialized = os.toByteArray();
BaseAnimal forWire = BaseAnimal.parseFrom(catSerialized);
assertEquals("CAT", forWire.getSpecies());
os = new ByteArrayOutputStream(1024);
forWire.writeTo(os);
byte[] wireData = os.toByteArray();
BaseAnimal fromWire = BaseAnimal.parseFrom(wireData);
assertEquals("CAT", fromWire.getSpecies());
Cat deserializedCat = Cat.parseFrom(wireData);
assertEquals("CAT", deserializedCat.getSpecies());
assertEquals("spotted", deserializedCat.getColoring());
整个技巧在于proto3绑定保留它们不理解的属性,并根据需要对它们进行序列化。通过这种方式,可以实现proto3转换(转换)而不会丢失数据。
请注意,“proto3转换”是非常不安全的操作,应该在进行鉴别器检查之后才能应用。在我的示例中,您可以将猫转换为狗而不会出现问题。下面的代码会失败。
try {
Dog d = Dog.parseFrom(wireData);
fail();
} catch(Exception e) {
}
当相同索引的属性类型匹配时,可能会出现语义错误。例如,在我所拥有的示例中,索引10在dog中是int64或在cat中是string,proto3会将它们视为不同的字段,因为它们在传输时的类型代码不同。在某些情况下,如果类型是字符串并且结构体,则proto3实际上可能会抛出一些异常或产生完全垃圾的结果。