0

I am trying to convert json to proto message object, but if there are some characters in json like $ or . or _ I get an InvalidProtocolBufferException. My proto:

syntax = "proto3";

package messages;
option java_multiple_files = true;

message Main {
    A a = 1;
}

message A {
    repeated B b = 1;
}

message B {
    repeated C c = 1;
}

message C {
    map<string, bytes> d = 1;
}

Java code:

 String json = "{\n" +
        "  \"a\" : {\n" +
        "    \"b\" : [ {\n" +
        "      \"c\" : [ {\n" +
        "        \"d\" : {\n" +
        "          \"money\" : [ \"100$\" ]\n" +
        "        }\n" +
        "      } ]\n" +
        "    } ]\n" +
        "  }\n" +
        "}";
    Main.Builder builder = Main.newBuilder();
    JsonFormat.parser().merge(json, builder);
    System.out.println(builder.build());

output:

  com.google.protobuf.InvalidProtocolBufferException: com.google.common.io.BaseEncoding$DecodingException: Unrecognized character: $

        at com.google.protobuf.util.JsonFormat$ParserImpl.merge(JsonFormat.java:1065)
        at com.google.protobuf.util.JsonFormat$Parser.merge(JsonFormat.java:273)
idmitriev
  • 4,619
  • 4
  • 28
  • 44

1 Answers1

0

In my opinion your problem is connected with declaration of type C, inside of it in proto definiton you have map<string,bytes> d = 1; Which on Java side will be: Map<String, ByteString> And In your Json you have something that "looks like" String-String map.

Let's do quick experiment and try to convert your Main type into json:

Main main = Main.newBuilder().setA(
        A.newBuilder().addB(
                B.newBuilder().addC(
                        C.newBuilder().putD("money", 
                                ByteString.copyFrom("100$".getBytes()))
                )
        )
).build();

System.out.println(JsonFormat.printer().print(main));

The output will be

{
  "a": {
    "b": [{
      "c": [{
        "d": {
          "money": "MTAwJA=="
        }
      }]
    }]
  }
}

As you can see we don't have 100$ but encoded version MTAwJA== and if you will try to convert this json to object using protobuf you will not have an error.

So in my opinion - either encode values in your d map during conversion to json (or convert to json using protobuf), or change protobuf declaration

  • Thank you Michal, I got it as you, I think it's impossible to convert from json to proto using JsonFormat in this case. I just wanna map java.lang.Object to proto message. I have a data object with Map data and I need to send it using protobuf. – idmitriev Feb 17 '17 at 20:59
  • In my opinion it wll not be possible without additional processing of json (on sender side), or without change in proto definition. It is possible that in your case, on sender side you can also use protobuf to serialize to json? – Michał Przybylak Feb 17 '17 at 21:08
  • yeah, on both sides I use protobuf. I can do it anyway, but I have not known the right way yet. Now I decided to map it as map as I got an answer from there - http://stackoverflow.com/questions/41878400/how-to-map-java-lang-object-in-proto-file-protobuf – idmitriev Feb 17 '17 at 21:11
  • Ok, sorry - I did not understand you in the first place. I assume that it is not possible for your "object" to become protobuf object? If not so probably (as it was mentioned in link you've gave) you will need to serialize your object into byte array – Michał Przybylak Feb 17 '17 at 21:20
  • Yeah, that's how I did - map – idmitriev Feb 18 '17 at 08:43
  • The bottom line is I can't use this json transformation with string type (100$) to Message type byte. I should use create message manually - ByteStream.copyFrom("100$".getBytes()) – idmitriev Feb 18 '17 at 08:47