nevi_me
nevi_me

Reputation: 2730

Java: protobuf from string

I'm using proto3 with grpc, and I'm looking at a more efficient way of creating a protobuf message without using a builder and populating it.

If I have a string (from Message.toString()), can I recreate the message with the string?

If I have a message type

message TestMessage {
    bool status = 1;
    uint64 created = 2;
    TestNested submessage = 3;


    message TestNested {
        int32 messageNumber = 1;
        Entry entry = 2;
    }

    message Entry {
        int32 id = 1;
        EntryType entryType = 2;
    }

    enum EntryType {
        DEFAULT_ENTRY = 0;
        OTHER_ENTRY = 1;
    }
}

and the below output:

status: true
created: 1534240073415
submessage {
  messageNumber: 3
  entry{
    id: 47957
    entryType: DEFAULT_ENTRY
  }
}

How can I create the TestMessage? I've looked at the JavaDoc to see if there's a parseFrom() method that takes in a string, but I'm not winning.

Upvotes: 9

Views: 21575

Answers (2)

codester
codester

Reputation: 11

Below code snippet / client codes for various cases conversions between 'plain test format' to proto values. Most of the things are obvious in the protobuf documentation.

Proto file: phonemetadatabrokerproto.proto

message CastAroundCriteria {
  optional string region_code = 1;
  optional int32 prefix = 2;
}
  public static void main(String args[]) {

    // Creating a value object in program through proto APIs.
    Phonemetadatabrokerproto.CastAroundCriteria cacb = Phonemetadatabrokerproto.CastAroundCriteria.newBuilder().setRegionCode("AE").setPrefix(20).build();
    System.out.println(cacb);

    // To travel over the wire as Byte string. Not in plain text, so not using special TextFormat kind of APIs. You have many other alternatives, please serach.
    Phonemetadatabrokerproto.CastAroundCriteria cacb2 = null;
    try{
    cacb2 = Phonemetadatabrokerproto.CastAroundCriteria.parseFrom(cacb.toByteString());
      } catch (InvalidProtocolBufferException e) {
      e.printStackTrace();
    }
    System.out.println(cacb2);

    // When vanilla string literals has to be passed between the APIs / on wire. Using TextFormat APIs
    CharSequence inputCS = cacb.toString();
    Phonemetadatabrokerproto.CastAroundCriteria.Builder cacb3 = null;
        try{
    cacb3 = Phonemetadatabrokerproto.CastAroundCriteria.newBuilder();
    TextFormat.getParser().merge(inputCS, cacb3);
        } catch (Exception e) {
      e.printStackTrace();
    }
    System.out.println(cacb3);

    // Hardcoded string unmarshalling to proto.
    CharSequence rawInput = "region_code: \"AE\" prefix: 20";
    Phonemetadatabrokerproto.CastAroundCriteria.Builder cacb4 = null;
        try{
    cacb4 = Phonemetadatabrokerproto.CastAroundCriteria.newBuilder();
    TextFormat.getParser().merge(rawInput, cacb4);
        } catch (Exception e) {
      e.printStackTrace();
    }
    System.out.println(cacb4);

    // Dynamic commandline input has to be string literal "region_code: 'AE' prefix: 20" when running in linux. Otherwise we need to escape \" in
    // command input. More of bash is culprit. :)
    CharSequence cmdInput = args[0];
    Phonemetadatabrokerproto.CastAroundCriteria.Builder cacb5 = null;
        try{
    cacb5 = Phonemetadatabrokerproto.CastAroundCriteria.newBuilder();
    TextFormat.getParser().merge(cmdInput, cacb5);
        } catch (Exception e) {
      e.printStackTrace();
    }
    System.out.println(cacb5);
  }

Please ignore some of the naming conventions, like class name is Phonemetadatabrokerproto and also exception handling.

Upvotes: 1

nevi_me
nevi_me

Reputation: 2730

I was looking for the TextFormat parser. The format that Message.toString() prints is the TextFormat representation.

To convert back to a protobuf message, I did the below:

TestMessage testMessage = new TestMessage.newBuilder();

CharSequence myText = "status: true\n ...";

com.google.protobuf.TextFormat.getParser().merge(myText, testMessage);

Upvotes: 12

Related Questions