La risposta potrebbe essere un po 'in ritardo ma forse questo aiuta ancora qualcuno.
Nella versione corrente di Protocol Buffers 3 pack
e unpack
sono available in Java.
Nel tuo esempio di imballaggio può essere fatto come:
Any anyMessage = Any.pack(protoMess.build()));
e disfare come:
ProtoMess protoMess = anyMessage.unpack(ProtoMess.class);
Anche qui è un esempio completo per la gestione dei messaggi di protocollo buffer con annidati Any
messaggi:
Protocolli File buffer
un semplice file buffer di protocollo con un Any
messaggio nidificato potrebbe essere simile:
syntax = "proto3";
import "google/protobuf/any.proto";
message ParentMessage {
string text = 1;
google.protobuf.Any childMessage = 2;
}
Un possibile messaggio nidificato potrebbe quindi essere:
syntax = "proto3";
message ChildMessage {
string text = 1;
}
imballaggio
Per costruire l'intero messaggio del può essere utilizzata la seguente funzione:
public ParentMessage createMessage() {
// Create child message
ChildMessage.Builder childMessageBuilder = ChildMessage.newBuilder();
childMessageBuilder.setText("Child Text");
// Create parent message
ParentMessage.Builder parentMessageBuilder = ParentMessage.newBuilder();
parentMessageBuilder.setText("Parent Text");
parentMessageBuilder.setChildMessage(Any.pack(childMessageBuilder.build()));
// Return message
return parentMessageBuilder.build();
}
disimballaggio
Per leggere il messaggio bambino dal messaggio genitore la seguente funzione può essere utilizzata:
public ChildMessage readChildMessage(ParentMessage parentMessage) {
try {
return parentMessage.getChildMessage().unpack(ChildMessage.class);
} catch (InvalidProtocolBufferException e) {
e.printStackTrace();
return null;
}
}
EDIT:
Se i messaggi confezionati possono avere diversi tipi, si può leggere il typeUrl
e utilizzare la riflessione per decomprimere il messaggio.Supponendo di avere i messaggi bambino ChildMessage1
e ChildMessage2
è possibile effettuare le seguenti operazioni:
@SuppressWarnings("unchecked")
public Message readChildMessage(ParentMessage parentMessage) {
try {
Any childMessage = parentMessage.getChildMessage();
String clazzName = childMessage.getTypeUrl().split("/")[1];
String clazzPackage = String.format("package.%s", clazzName);
Class<Message> clazz = (Class<Message>) Class.forName(clazzPackage);
return childMessage.unpack(clazz);
} catch (ClassNotFoundException | InvalidProtocolBufferException e) {
e.printStackTrace();
return null;
}
}
Per ulteriori elaborazioni, è possibile determinare il tipo del messaggio con instanceof
, che non è molto efficiente. Se si desidera ottenere un messaggio di un certo tipo, si dovrebbe confrontare il typeUrl
direttamente:
public ChildMessage1 readChildMessage(ParentMessage parentMessage) {
try {
Any childMessage = parentMessage.getChildMessage();
String clazzName = childMessage.getTypeUrl().split("/")[1];
if (clazzName.equals("ChildMessage1")) {
return childMessage.unpack("ChildMessage1.class");
}
return null
} catch (InvalidProtocolBufferException e) {
e.printStackTrace();
return null;
}
}
Non c'è altra via che questa 'readChildMessage'? Cosa succede se ci sono decine di messaggi diversi che potrebbero entrare? Basta aggiungere nuovi blocchi 'try-catch'? Anche 'switch-case' e simili sono assolutamente inaccettabili. – Sorona
Buona domanda, ho dimenticato di aggiungere che è possibile ottenere il nome del messaggio imballato come 'typeURL'. Ciò consente di decomprimere qualsiasi messaggio tramite riflessione o decidere direttamente cosa fare con il messaggio. Ho aggiunto due esempi alla mia risposta, spero che questo aiuti. – sundance
Ottimo! Mi ha aiutato! – FisherCoder