C++ reflection problem

494 views
Skip to first unread message

John Coffey

unread,
Mar 15, 2016, 3:32:07 PM3/15/16
to Protocol Buffers
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()) {



Feng Xiao

unread,
Mar 18, 2016, 7:18:09 PM3/18/16
to Protocol Buffers


On Tuesday, March 15, 2016 at 12:32:07 PM UTC-7, John Coffey wrote:
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?
Yeah, it's working as intended.
 
How should I change to handle a situation where fields can contain empty strings and be gettable via reflection.  
You can use google.protobuf.StringValue instead:

The idea is that message fields in proto3 still support field presence, so you can query whether a message field is set or not.
Reply all
Reply to author
Forward
0 new messages