Vraag Upgraden van protobuf van versie 2 naar 3 - incompatibel met protobuf standaardwaarden


Ik probeer te upgraden naar het gebruik van protobuf versie 3, en blijf achterwaarts compatibel met versie 2. Lijkt te werken, behalve één ding - in proto-2 zou je je eigen standaardwaarden kunnen instellen, maar in proto 3 kun je niet. Als u in proto-2 een standaardwaarde hebt gekozen die niet de standaard standaardwaarde is in proto-3, heeft u een probleem. Bijvoorbeeld in proto-2:

message Record {
  required uint32 fileno = 1;               
  required uint64 pos = 2;                  
  optional uint64 bmsPos = 3 [default = 0]; 
  optional uint32 scanMode = 4 [default = 9999];  
}

nu moet proto-3 zijn:

message Record {
  uint32 fileno = 1;               
  uint64 pos = 2;                  
  uint64 bmsPos = 3; 
  uint32 scanMode = 4;  
}

In zowel proto-2 als proto-3 worden ontbrekende waarden niet in het bericht verzonden. Maar de proto-3 API vertelt u niet of de standaardwaarde in het bericht staat of niet, maar vertelt u alleen de waarde.

Dus de proto-3-ontvanger krijgt een bericht en vertelt me ​​dat scanMode = 0. Als dat bericht afkomstig was van een proto-2-zender, dan 1) de proto-2-zender plaatste een 0 in het bericht, of 2) het prototype 2 verzender zet de waarde op 9999 (de standaardwaarde), en dus wordt de waarde niet verzonden, en de proto-3-ontvanger interpreteert het als een 0. Zonder te weten of de waarde aanwezig is in het bericht of niet, kan mijn code niet disambigueren , zelfs als het weet of het bericht afkomstig was van een proto-2 of proto-3 zender.

Merk op dat er geen probleem is met het bmsPos-veld in het voorbeeld, omdat het proto-2-bericht dezelfde standaardwaarde gebruikt als proto-3 (0). Maar als je toevallig een standaardwaarde hebt gekozen die niet hetzelfde is als proto-3, dan zie ik niet hoe ik moet upgraden naar proto-3 en achterwaarts compatibel moet zijn.


28
2017-10-18 23:17


oorsprong


antwoorden:


Blijkt dat er een manier is om erachter te komen of een standaardwaarde daadwerkelijk ontbreekt of niet (dankzij een paar vrienden op google voor dit antwoord):

message Record {
  uint32 fileno = 1;               
  uint64 pos = 2;                  
  uint64 bmsPos = 3; 
  oneof scanMode_present {
    uint32 scanMode = 4;
  }
  uint32 version = 5; // set to >= 3 for protobuf 3 
}

De genereercode heeft aanvullende methoden om te detecteren of een van de velden worden ingesteld, met behulp van de getXXXcase () methode:

int scanMode = proto.getScanMode();
boolean isMissing = proto.getScanModePresentCase() == Record.ScanModePresentCase.SCANMODEPRESENT_NOT_SET;
if (isMissing) {
  boolean isProto3 = proto.getVersion() >= 3;
  scanMode = (isProto3) ? 0 : 9999;
}
  • Merk op dat de naam van de een van de is willekeurig, ik heb de conventie aangenomen fieldname_present.
  • De een van de voegt niets toe aan het draadformaat, zodat het compatibel blijft met de proto-2 berichten.
  • U kunt de versie info ergens dat zinvol is, ik zet het in het Record-bericht voor dit voorbeeld.

Met deze 'truc' heb ik een upgrade uitgevoerd naar proto-3 met achterwaartse compatibiliteit met niet-standaard proto-2 standaardwaarden.


34
2017-10-18 23:40