クリーンな方法はありませんが、ハックな方法がいくつかあります。1 つは、次のような 2 番目のメッセージを定義することです。
message RawOuter {
repeated bytes inners = 1;
// ... same fields as Outer ...
}
RawOuter
は、繰り返しフィールドが type から type に変更されたことをOuter
除いて、と同じです。のエンコードされたインスタンスを入力してからシリアル化すると、解析されたバージョンで を構築した場合とまったく同じ結果が得られます。つまり、ネストされたメッセージのワイヤ フォーマットは、そのネストされたメッセージのシリアル化を含むフィールドのワイヤ フォーマットと同じです。これは、protobuf エンコーディングの面白い悪用可能な癖の 1 つです。inners
Inner
bytes
inners
Inner
RawOuter
Outer
bytes
ただし、このハックにはいくつかの問題があります。特に、他のプロトに埋め込まれたインスタンスを構築しようとしている場合は、うまく機能しません。これは、含まれているすべてのメッセージの 2 つのコピー (1 つは を使用し、もう 1Outer
つは を使用) を保持したくない可能性があるためです。Outer
RawOuter
Outer
別のさらにハックなオプションは、エンコードされたメッセージをインスタンスのに挿入することUnknownFieldSet
です。
Outer outer;
for (auto& inner: inners) {
outer.mutable_unknown_fields()
->AddLengthDelimited(1, inner);
}
はUnknownFieldSet
、ファイルで定義されている既知のフィールド番号と一致しない、解析中に表示されるフィールドを格納することを目的としてい.proto
ます。これにより、プロトコルに新しいフィールドを追加するたびにプロキシを再コンパイルすることなく、単にメッセージを受信して別のサーバーに転送するプロキシ サーバーを作成できるようになるという考えです。ここでは、実際に既知のフィールドに対応する値をそれに貼り付けることで悪用していますが、実装は気付かないため、これらのフィールドは問題なく書き出されます。
このアプローチの主な問題は、値が実際には別の場所に隠されているためOuter
、その間に他の誰かがあなたのインスタンスを検査すると、リストが空であるかのように見えることです。inners
これはかなり醜いハックであり、後であなたを悩ませることになるでしょう。パフォーマンスの違いを測定し、それが大きいことがわかった場合にのみお勧めします。
また、シリアライゼーション コードは常に未知のフィールドを最後に書き込みますが、既知のフィールドはフィールド番号順に書き込みます。パーサーは任意の順序を受け入れることになっていますが、解析されていないデータをハッシュ マップのキーなどとして使用していて、フィールドの順序を変更すると完全に壊れてしまう人がいることがあります。
ところで、文字列をコピーするのではなく所定の位置に交換することで、これらの両方のアプローチのパフォーマンスを向上させることができます。つまり、
raw_outer->add_inners()->swap(inner);
また
outer->mutable_unknown_fields()->AddLengthDelimited(1)->swap(inner);