For future students of the course "Java Developer. Professional" prepared a translation of the material.
We also invite you to attend an open webinar on the topic "gRPC for microservices or non-REST single" . At an open webinar, we'll see what gRPC is and how it can be used (or can it?) Instead of REST for communication between microservices.
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
:
-
null
(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:
, .
.
FieldMaskUtil
.
.
.
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());
}
, .
.
, .
.
:
.
.
:
FieldMask
.
, .
.
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
, .
.
.
has
.
.
.
:
.
.
:
:
has
, .
.
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?
"Java Developer. Professional".