Protobuf 3.0 Any type of packaging / unpacking

I would like to know how to convert the Protobuf Any type to the original Protobuf message type and vice versa. In Java, from Message to Any is easy:

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

But how can I make out that Any is back to the original message (for example, to type "protoMess")? I could probably parse everything on the stream just to read it, but that’s not what I want. I want to do the following conversion:

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

How can i achieve this? Is it already implemented for Java? The Protobuf Language Guide says that there are batch and unpack methods, but in Java they are not. Thanks in Advance :)

+7
alpha unpack pack protocol-buffers any
source share
1 answer

The answer may be a bit belated, but maybe it still helps someone.

In the current version of protocol buffers, 3 pack and unpack are available in Java .

In your example, packaging can be done as follows:

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

And unpack as:

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

Here is also a complete example of processing protocol buffer messages with nested Any messages:

Buffers Files

A simple protocol buffer file with an Any message attached may look like this:

 syntax = "proto3"; import "google/protobuf/any.proto"; message ParentMessage { string text = 1; google.protobuf.Any childMessage = 2; } 

A possible attached message may be as follows:

 syntax = "proto3"; message ChildMessage { string text = 1; } 

Packaging

To create a complete message, you can use the following function:

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

Unpacking

To read the child message from the parent message, you can use the following function:

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

EDIT:

If your packed messages can have different types, you can read typeUrl and use reflection to unpack the message. Assuming you have child messages ChildMessage1 and ChildMessage2 , you can do the following:

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

For further processing, you can determine the type of message with instanceof , which is not very efficient. If you want to receive a message of a certain type, you must directly compare typeUrl :

 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; } } 
+7
source share

All Articles