介绍介绍日后再补TODO,总之想要了解protobuf的工作原理,需要首先知道编程中的“Builder模式”——由于类属性过多而出现的一种较好的解决方式。没有公有构造函数,设置属性仅能通过Builder的set类方法等等。具体可查阅资料学习。 这里介绍一下protobuf生成的Java对象结构。 .proto假设protobuf定义文件如下: option java_outer_classname = "Test";message A { required string a = 1; message B1 { optional string b = 1; message C { optional string c = 1; } optional C c = 2; } optional B1 b1 = 2; message B2 { optional int32 b = 1; } optional B2 b2 = 3; optional int32 num = 4; } 则会生成类名为 Java对象中的方法主要看一下生成的对象中,都有哪些方法可供使用。由于生成的Java文件太大,就不再贴上来了。 methods in interface首先,针对最外层,会生成 接口中包含的方法基本都是获取各个属性的—— 如果属性是结构体型的,比如对于b1,其类型为B1,那么接口中会有 methods in object对于object,比如类型A,主要有以下几种类型的方法—— object本身的特性: 对属性的get方法: 转换方法: object对象是不可变的,无法做到对属性的值进行删改,只能查询。删改只有通过Builder才能做到。 methods in Builder对于Builder,比如A.Builder,主要有以下几种类型的方法—— 查询属性: 删改属性。比如对于A的属性a,有: 转换方法: Builder本身的一些方法: 最值得注意的是, 比如给出A.Builder,想要修改其中的属性b1的属性b: aBuilder.getB1Builder().setB("convenint_set") 就完成了对值的修改。 否则,需要这样去修改: Test.A.B1.Builder b1Builder = aBuilder.getB1().toBuilder().setB("change_only_if_set_again");aBuilder.setB1(b1Builder); // 使用b1或b1Builder都行,有重载方法
所以使用builder获取深层次builder并修改,是非常方便的,尤其是在嵌套层级比较深的情况下。 再比如,想要修改其中的属性b1的属性c的属性c,只需: aBuilder.getB1Builder().getCBuilder().setC("builder_get_builder") 就完成了对值的修改。 示例/** * @author liuhaibo on 2018/06/27 */public class Main { public static void main(String... args) { Test.A.B1.C cObject = Test.A.B1.C.newBuilder().setC("c").build(); Test.A.B1 b1Object = Test.A.B1.newBuilder().setB("b").setC(cObject).build(); Test.A.B2 b2Object = Test.A.B2.newBuilder().setB(1).build(); Test.A aObject = Test.A.newBuilder().setA("a").setB1(b1Object).setB2(b2Object).build(); System.out.println("///* Methods for object *///"); methodsForObject(aObject); System.out.println("///* Methods for Builder *///"); methodsForBuilder(aObject, b1Object); } private static void methodsForObject(Test.A aObject) { System.out.println("A = " + aObject); System.out.println("A.isInitialized() = " + aObject.isInitialized()); // Exception in thread "main" com.google.protobuf.UninitializedMessageException: Message missing required fields: a // System.out.println("A(without a field).isInitialized() = " + aObject.toBuilder().clearA().build().isInitialized()); System.out.println("A.getSerializedSize() = " + aObject.getSerializedSize()); System.out.println("A.Builder = " + aObject.toBuilder()); System.out.println("A.getB1OrBuilder() = " + aObject.getB1OrBuilder()); System.out.println("A.b1 = " + aObject.getB1()); } private static void methodsForBuilder(Test.A aObject, Test.A.B1 b1Object) { // builder Test.A.Builder aBuilder = Test.A.newBuilder(); // merge from a existing object aBuilder.mergeFrom(aObject); System.out.println(aBuilder); // change a structure in object aBuilder.mergeB1(b1Object.toBuilder().setB("change_a_structure").build()); System.out.println(aBuilder); // 用builder去get builder,需要修改值直接set就可以了 aBuilder.getB1Builder().getCBuilder().setC("builder_get_builder").build(); System.out.println(aBuilder); // 用object去toBuilder,再set值,那么原本的object不会变 aBuilder.getB1().toBuilder().setB("no_change_happens"); System.out.println(aBuilder); // 除非再set回去 Test.A.B1.Builder b1Builder = aBuilder.getB1().toBuilder().setB("change_only_if_set_again"); aBuilder.setB1(b1Builder); // 使用b1或b1Builder都行,有重载方法 System.out.println(aBuilder); // buildPartial() vs. build() aBuilder.clearA().getB1Builder().getCBuilder().setC("2333"); // 现在已经是CBuilder对象了,不再是ABuilder,所以调用build()也是CBuilder的方法 // safe System.out.println(aBuilder.buildPartial()); aBuilder.clearA(); // Exception in thread "main" com.google.protobuf.UninitializedMessageException: Message missing required fields: a // System.out.println(aBuilder.build()); } } 参阅 |
|
来自: jasonbetter > 《Now》