Dukungan nol di Protobuf

Untuk calon mahasiswa kursus "Java Developer. Professional" menyiapkan terjemahan materi.



Kami juga mengundang Anda untuk menghadiri webinar terbuka dengan topik
"gRPC untuk layanan mikro atau tunggal non-REST" . Pada webinar terbuka, kita akan melihat apa itu gRPC dan bagaimana gRPC dapat digunakan (atau bisakah?) Daripada REST untuk komunikasi antar layanan mikro.






Protocol Buffer / gRPC:





service MyDataService {
  rpc UpateMyData (UpdateMyDataRequest) 
     returns (UpdateMyDataResponse);
}
message MyData {
  int32 id = 1;
  string stringValue = 2;
  SubData subData = 3;
}

message SubData {
 int64 bigValue = 1;
}
message UpdateMyDataRequest {
  MyData update = 1;
}
      
      



, MyData.stringValue



. , , - :





UpdateMyDataRequest request = UpdateMyDataRequest.newBuilder()
  .setUpdate(MyData.newBuilder()
    .setId(id)
    .setStringValue(null)
  )

serviceFutureStub.update(request)
      
      



NullPointerException







, protoc



, null



NullPointerException



. , null



. , get



.





UpdateMyDataRequest.newBuilder().build().getStringValue() == ""
      
      



null Protocol Buffers?

.





null?





, null :





  • Null β€” null.





  • Null β€” / .





  • Null β€” .





  • Null β€” .





, protobuf null. protobuf , Protobuf / gRPC API.





null , Protobuf.





proto3. proto2 , .





proto3

:









  1. null





  2. (0, . .) 





Null β€” Null ( OneOf NullValue)

null . , null . , MyData.stringValue



null.





Json- MyData :





{
  "id": 123
  "stringValue": null
}
      
      



, null. , null - . , nullable-. , Kotlin, .





Protobuf:





syntax = "proto3";

package io.github.efenglu.protobuf.examples.oneof;

option java_multiple_files = true;

import "google/protobuf/struct.proto";

service MyDataService {
  rpc UpateMyData (UpdateMyDataRequest) 
     returns (UpdateMyDataResponse);
}

message MyData {
  int32 intValue = 1;
  NullableString stringValue = 2;
  NullableSubData subData = 3;
}

message SubData {
  int64 bigValue = 1;
}

message NullableSubData {
  oneof kind {
    google.protobuf.NullValue null = 1;
    SubData data = 2;
  }
}

message NullableString {
  oneof kind {
    google.protobuf.NullValue null = 1;
    string data = 2;
  }
}

message UpdateMyDataRequest {
 MyData data = 1;
}


message UpdateMyDataResponse {

}
      
      



β€œnullable” :





  • NullableString







  • NullableSubData







oneof :





  • Null





  • null





Oneof



, null null.





Java- :





null:

UpdateMyDataRequest request = UpdateMyDataRequest.newBuilder()
  .setData(MyData.newBuilder()
    .setStringValue(NullableString.newBuilder()
      .setNull(NullValue.NULL_VALUE)
      .build()
    )
    .setSubData(NullableSubData.newBuilder()
      .setNull(NullValue.NULL_VALUE)
      .build()
    ).build()
).build();

service.upateMyData(request);
      
      



, null setNull



.





null :

UpdateMyDataRequest request = UpdateMyDataRequest.newBuilder()
  .setData(MyData.newBuilder()
    .setStringValue(NullableString.newBuilder()
      .setData("hello")
      .build()
    )
    .setSubData(NullableSubData.newBuilder()
      .setData(SubData.newBuilder()
        .setBigValue(1234567)
      .build()
    ).build()
  ).build()
).build();

service.upateMyData(request);
      
      



, setData



.





:

if (request.hasData()) {

  if (request.getData().hasStringValue()) {
    final String nullableString;
    if (request.getData().getStringValue().hasNull()) {
      nullableString = null;
    } else {
      nullableString = request.getData()
        .getStringValue()
        .getData();
      }
  }

  if (request.getData().hasSubData()) {
    final SubData nullableSubData;
    if (request.getData().getSubData().hasNull()) {
      nullableSubData = null;
    } else {
      nullableSubData = request.getData()
       .getSubData()
       .getData();
    }
  }

}
      
      



, null ( null), .





:





  • , null, , null.





  • null





:





  • null









Null : FieldMask

, / , .





null , . , null , , null, . json-.





{
 "id": 123
 -- ommited "stringValue" --
}
      
      



proto, , .





Protobuf:

service MyDataService {
  rpc Update (UpdateMyDataRequest) returns (UpdateMyDataResponse);
  rpc List (ListMyDataRequest) returns (ListMyDataResponse);
}

message MyData {
  int32 id = 1;
  string stringValue = 2;
  SubData subData = 3;
}

message SubData {
  int64 bigValue = 1;
}

message UpdateMyDataRequest {
  MyData update = 1;
  google.protobuf.FieldMask field_mask = 2;
}

message UpdateMyDataResponse {
  MyData new_data = 1;
}

message ListMyDataRequest {
  int32 id = 1;
  google.protobuf.FieldMask field_mask = 2;
}

message ListMyDataResponse {
  repeated MyData data = 1;
}
      
      



, UpdateMyDataRequest



ListMyDataRequest



FieldMask



. , , .





:





MyData sendUpdate(int id, String value) {
  UpdateMyDataRequest request = UpdateMyDataRequest.newBuilder()
    .setUpdate(MyData.newBuilder()
      .setId(id)
      .setStringValue(value)
    )
    .setFieldMask(FieldMaskUtil.fromFieldNumbers(
      MyData.class, 
      MyData.STRINGVALUE_FIELD_NUMBER)
    )
    .build();

  return serviceFutureStub.update(request).getNewData();
}

List<MyData> listOnlySubData(int id) {
  ListMyDataRequest request = ListMyDataRequest.newBuilder()
    .setId(id)
    .setFieldMask(FieldMaskUtil.fromFieldNumbers(
      MyData.class, 
      MyData.SUBDATA_FIELD_NUMBER)
    )
    .build();

  return serviceFutureStub.list(request).getDataList();
}
      
      



:





@Override
public void update(
  UpdateMyDataRequest request,
  StreamObserver<UpdateMyDataResponse> responseObserver
) {

  MyData updateData = request.getUpdate();
  FieldMask fieldMask = request.getFieldMask();

  // Fetch exiting Values
  MyData existing = repo.readData(updateData.getId());
  MyData.Builder builder = existing.toBuilder();

  // Update only the fields listed in the fieldmask
  FieldMaskUtil.merge(fieldMask, updateData, builder);

  // Store the result
  repo.writeData(builder.build());

  // Send the new state back
  responseObserver.onNext(UpdateMyDataResponse.newBuilder()
    .setNewData(builder)
    .build()
  );
}
      
      



update:





  1. , .





  2. .





  3. FieldMaskUtil



    .





  4. .





  5. .





FieldMaskUtil



, , , .





@Override
public void list(
  ListMyDataRequest request,
  StreamObserver<ListMyDataResponse> responseObserver
) {
  int id = request.getId();
  FieldMask fieldMask = request.getFieldMask();
  // Fetch the list
  List<MyData> result = repo.listData(id);

  ListMyDataResponse.Builder response = 
    ListMyDataRespons.newBuilder();
  MyData.Builder builder = MyData.newBuilder();
  for (MyData data : result) {
    builder.clear();

    // Use the field mask to send back ONLY the data requested
    FieldMaskUtil.merge(fieldMask, data, builder);

    response.addData(builder);
  }

  // Send the filtered list back
  responseObserver.onNext(response.build());
}
      
      



, .





  1. .





  2. , .





  3. .





:





  1. .





  2. .





:





  1. FieldMask



    .





  2. , .





  3. .





Null : Has

"has



", boolean. (β€œhas been set



”), true



. , , . , , .





, , Message. , Proto3 (wrapper) .





...

import "google/protobuf/wrappers.proto";

service MyDataService {
  rpc Update (UpdateMyDataRequest) returns (UpdateMyDataResponse);
}
...
message UpdateMyDataRequest {
  int32 id = 1;
  google.protobuf.StringValue stringValue = 2;
  UpdateSubData subData = 3;
}

message UpdateSubData {
  google.protobuf.Int64Value bigValue = 1;
}
...
      
      



google/protobuf/wrappers.proto



google.protobuf.StringValue



google.protobuf.Int64Value



. , "has



".





:

void update() {
  service.update(UpdateMyDataRequest.newBuilder()
    .setStringValue(StringValue.of("customValue"))
    .build()
  );
}
      
      



, . β€” StringValue



.





, (pre-auto boxing) Java, .





:

@Override
public void update(
  UpdateMyDataRequest request,
  StreamObserver<UpdateMyDataResponse> responseObserver) {

  // Fetch exiting Values
  MyData existing = repo.readData(request.getId());
  MyData.Builder builder = existing.toBuilder();

  // Update Fields as necessary
  if (request.hasStringValue()) {
    builder.setStringValue(request.getStringValue().getValue());
  }

  if (request.hasSubData()) {
    if (request.getSubData().hasBigValue()) {
      builder.setSubData(
        builder.getSubData().toBuilder()
          .setBigValue(request.getSubData()
            .getBigValue()
            .getValue()
          )
        );
      }
  }

  repo.writeData(builder.build());

  responseObserver.onNext(UpdateMyDataResponse.newBuilder()
    .setNewData(builder)
    .build()
  );
}
      
      



, FieldMaskUtil



, .





  1. .





  2. .





  3. has



    .





  4. .





  5. .





:





  1. .





  2. .





:





  1. : has



    , .





  2. .





Null :

, "" , . , !





.





: Β« , null.Β»





!





  • .





  • Proto3 , (0, "") , .





, .





"has



" . "has



" .





Null : Null-

:





String value;
if (value != null) {
  // insert value into database
}
      
      



- ?





  • ""



    ?





  • value " "



    ?





Protobuf , null. , null, , apache commons. 





String value;
if (StringUtils.isNotBlank(value)) {
  // insert value into database
}
      
      



, , value



.





" null" protoc .





:





  • Optional





protoc :





  • null get.





  • null .





  • "has



    " .





protoc How to customize the gRPC generated code.





? , Protocol Buffers null. .





Protocol buffers :





  • ?





  • null?





  • null?





Github. 






"Java Developer. Professional".





Β«gRPC REST- Β».








All Articles