Short answer
Yes, you should get a TProtocolException::INVALID_DATA
if the data are not present while deserializing. That's not the case in your example, so you don't get the exception.
Long answer
This is one of the generated C++ read()
methods based on your IDL. Watch out for isset_number
and how it is used:
uint32_t Sub::read(::apache::thrift::protocol::TProtocol* iprot) {
uint32_t xfer = 0;
std::string fname;
::apache::thrift::protocol::TType ftype;
int16_t fid;
xfer += iprot->readStructBegin(fname);
using ::apache::thrift::protocol::TProtocolException;
bool isset_number = false;
while (true)
{
xfer += iprot->readFieldBegin(fname, ftype, fid);
if (ftype == ::apache::thrift::protocol::T_STOP) {
break;
}
switch (fid)
{
case 1:
if (ftype == ::apache::thrift::protocol::T_I32) {
xfer += iprot->readI32(this->number);
isset_number = true;
} else {
xfer += iprot->skip(ftype);
}
break;
default:
xfer += iprot->skip(ftype);
break;
}
xfer += iprot->readFieldEnd();
}
xfer += iprot->readStructEnd();
if (!isset_number)
throw TProtocolException(TProtocolException::INVALID_DATA);
return xfer;
}
So why does it work in your example?
As we have seen, required
fields are expected to be present in the deserialized data, while optional
(and default) fields may be missing. But fields marked required
(and default fields) are also always written to the transport, optional
only when a value has been assigned. Hence you read the data that you serialized before:
uint32_t Sub::write(::apache::thrift::protocol::TProtocol* oprot) const {
uint32_t xfer = 0;
xfer += oprot->writeStructBegin("Sub");
xfer += oprot->writeFieldBegin("number", ::apache::thrift::protocol::T_I32, 1);
xfer += oprot->writeI32(this->number);
xfer += oprot->writeFieldEnd();
xfer += oprot->writeFieldStop();
xfer += oprot->writeStructEnd();
return xfer;
}
Note that Thrift does not care about whether the field contains valid data. It's all about the serializing aspect.
Recommended reading
Diwaker Gupta's "Missing Guide" explains the pros ands cons of required
quite good.