I wrote a C++ gRPC application using the latest protobuf master code base. The application is an RPC application that supports a couple of custom Message types (using protoc3 as required by gRPC)
One of these fields is a string. On the server when I set this value to std::string() - effectively an empty string.
Now on the client side, when this messge is received I use reflection to query the field, however as it is an empty string the reflection does not show the field, it only does so if the server sets the field so something non empty.
I thought that putting required on the field would do the trick, however this is no longer allowed in proto3. Is this working as designed, or an error? How should I change to handle a situation where fields can contain empty strings and be gettable via reflection.
I see the generated protobuf ias as follows - could there be some special meaning behind an empty string value and the GetEmptuStringAlreadyInited?
// THIS IS THE PROTOBUF GENERATED CODE
inline void OpSupportMessage::set_mserialnumber(const ::std::string& value) {
mserialnumber_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
// @@protoc_insertion_point(field_set:ca.OpSupportMessage.mSerialNumber)
}
// THIS IS MY MESSAGE DEFINITION PROTOC file
// protobuf message
message OpSupportMessage {
RXMessageType mMessageType = 1;
string mSerialNumber = 4;
string mDateTime = 6;
}
// THIS IS MY SERVER CODE
grpc::Status
CADaemon::GetOpSupportMessage(
ServerContext* context,
const::google::protobuf::Empty* request,
ca::OpSupportMessage* response)
{
// Critical Section - read access
boost::shared_lock<boost::shared_mutex> readLock(gRWMutexGuard);
// check to see if we are still waiting for the
// first DLMUWOperationalSupportMessage
if (mpOpSupportMessage) {
// set other fields...
. . .
response->set_mserialnumber(std::string()); // this does not show up in message descriptor
. . .
return grpc::Status::OK;
} else { // still waiting for the message
return grpc::Status(grpc::StatusCode::UNAVAILABLE,
"Waiting for first DLMUW Operational Support Message");
}
}
// THIS IS MY CLIENT CODE - highlighed fields array below only shows fields with non empty strings
std::unique_ptr<gp::Message> pMessage;
if (boost::istarts_with(fieldName, "osm_")) {
auto temp = caClient->getOpSupportMessage();
pMessage = unique_dynamic_cast<gp::Message, ca::OpSupportMessage> (temp);
} else {
auto temp = caClient->getMaintenanceOTPMessage();
pMessage = unique_dynamic_cast<gp::Message, ca::MaintenanceOTPMessage> (temp);
}
if (pMessage) {
// use reflection to get the string value
// from the received message, note this is not supported
// in the 'lite' variant, if memory is an issue, we can
// switch to the lite variant later by explicitly
// handling each switch case separately and explicitly
// fetching the field & converting the value to string
const auto reflection = pMessage->GetReflection();
std::vector<const FieldDescriptor*> fields;
pMessage->GetReflection()->ListFields(*pMessage, &fields);
const auto fieldIter = std::find_if(fields.cbegin(), fields.cend(),
[&lcFieldName](const FieldDescriptor* next) {
return boost::iequals(next->name(), lcFieldName);
});
if (fieldIter != fields.cend()) {
std::string result;
auto fieldDescriptor = *fieldIter;
if (!fieldDescriptor->is_repeated()) {
switch (fieldDescriptor->cpp_type()) {