2015-09-16 11 views
7

Chciałbym wiedzieć, jak przekształcić typ Protobuf Any na oryginalny typ wiadomości Protobuf i na odwrót. W języku Java z listu na inne jest proste:Protobuf 3.0 Any Type pack/unpack

Any.Builder anyBuilder = Any.newBuilder().mergeFrom(protoMess.build()); 

Ale jak mogę analizować że Wszelkie z powrotem do originial wiadomości (na przykład do rodzaju „protoMess”)? Mogłabym prawdopodobnie sparsować wszystko w strumieniu tylko po to, żeby go przeczytać, ale tego nie chcę. Chcę przeprowadzić transformację w następujący sposób:

ProtoMess.MessData.Builder protoMessBuilder = (ProtoMess.MessData.Builder) transformToMessageBuilder(anyBuilder) 

Jak mogę to osiągnąć? Czy jest już wdrożony dla Java? Protobuf Language Guide mówi, że były metody pakowania i rozpakowywania, ale nie ma ich w Javie. Z góry dziękuję :)

Odpowiedz

5

Odpowiedź może być nieco spóźniona, ale może to nadal pomaga komuś.

W bieżącej wersji buforów protokołów 3 pack i unpackavailable in Java.

W przykładzie pakowania można zrobić tak:

Any anyMessage = Any.pack(protoMess.build())); 

i rozpakowywanie jak:

ProtoMess protoMess = anyMessage.unpack(ProtoMess.class); 

Tutaj jest również pełny przykład do obsługi wiadomości protokołu buforów zagnieżdżonych Any komunikatów:

ProtocolBuffers Files

prosty protokół Zderzaki złożyć zagnieżdżonego Any wiadomości może wyglądać tak:

syntax = "proto3"; 

import "google/protobuf/any.proto"; 

message ParentMessage { 
    string text = 1; 
    google.protobuf.Any childMessage = 2; 
} 

Możliwym zagnieżdżony wiadomość może następnie być:

syntax = "proto3"; 

message ChildMessage { 
    string text = 1; 
} 

pakowania

Aby zbudować pełną wiadomość The można użyć następującej funkcji:

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(); 
} 

Rozpakowanie

Aby odczytać wiadomość dziecko od wiadomości dominującej następująca funkcja może być używany:

public ChildMessage readChildMessage(ParentMessage parentMessage) { 
    try { 
     return parentMessage.getChildMessage().unpack(ChildMessage.class); 
    } catch (InvalidProtocolBufferException e) { 
     e.printStackTrace(); 
     return null; 
    } 
} 

EDIT:

Jeśli pakowanych wiadomości mogą mieć różne typy, można przeczytaj typeUrl i użyj odbicia, aby rozpakować wiadomość.Zakładając, że masz wiadomości potomnych ChildMessage1 i ChildMessage2 można wykonać następujące czynności:

@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; 
    } 
} 

Dla dalszego przetwarzania, można określić typ wiadomości z instanceof, co nie jest bardzo skuteczny. Jeśli chcesz otrzymać wiadomość pewnego typu, należy porównać typeUrl bezpośrednio ze:

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; 
    } 
} 
+1

Czy nie ma innego sposobu niż ten 'readChildMessage'? Co jeśli mam dziesiątki różnych wiadomości, które mogą wejść? Po prostu dodaj nowe blokowanie "try-catch"? Nawet 'switch-case' i podobne są absolutnie niedopuszczalne. – Sorona

+0

Dobre pytanie, zapomniałem dodać, że można uzyskać nazwę upakowanej wiadomości jako 'typURL'. Pozwala to rozpakować dowolną wiadomość poprzez odbicie lub bezpośrednio zdecydować, co zrobić z wiadomością. Dodałem dwa przykłady do mojej odpowiedzi, mam nadzieję, że to pomoże. – sundance

+0

Świetnie! Pomogło mi! – FisherCoder