Search code examples
javaprotocol-buffersprotobuf-java

Convert Protobuf to Json without Quotes


ad_group {
  resource_name: "customers/8776659915/adGroups/143689544046"
  status: ENABLED
  type: VIDEO_TRUE_VIEW_IN_STREAM
  id: 143689544046
  name: "Video Consideration - 2023-01-06"
  base_ad_group: "customers/8776659915/adGroups/143689544046"
  campaign: "customers/8776659915/campaigns/19500015051"
  cpc_bid_micros: 0
  cpm_bid_micros: 10000
  target_cpa_micros: 0
  cpv_bid_micros: 567000000
  target_cpm_micros: 10000
  effective_target_cpa_micros: 0
}

This is the Protobuf that I have and I'm using com.google.protobuf.util.JsonFormat to convert it to Json. Here's the code snippet:

String jsonString = JsonFormat.printer().print(googleAdsRow);

And the JSON String looks like this:

{
  "adGroup": {
    "resourceName": "customers/8776659915/adGroups/143689544046",
    "status": "ENABLED",
    "type": "VIDEO_TRUE_VIEW_IN_STREAM",
    "id": "143689544046",
    "name": "Video Consideration - 2023-01-06",
    "baseAdGroup": "customers/8776659915/adGroups/143689544046",
    "campaign": "customers/8776659915/campaigns/19500015051",
    "cpcBidMicros": "0",
    "cpmBidMicros": "10000",
    "targetCpaMicros": "0",
    "cpvBidMicros": "567000000",
    "targetCpmMicros": "10000",
    "effectiveTargetCpaMicros": "0"
  }
}

The problem is that all the values have been converted to String by default. Is there any way we can convert values with the actual datatype and not String by default?

I see there's a printSingleFieldValue method that accepts alwaysWithQuotes a boolean as a parameter in JsonFormat.PrinterImpl that is used to add quotes, but I am not being able to figure out a way to reach there. Any suggestions will be appreciated. Thanks in advance.


Solution

  • It's a matter of specification: from the docs:

    "The JSON format follows Proto3 JSON specification and only proto3 features are supported."

    This means that someone has decided how protobuf objects are to be represented in JSON, and they chose this way. The purpose for doing so is that any protobuf object serialised to JSON will be in a standard form of JSON, and thus guaranteeed to be de-serialisable by protobuf code. If you started tampering with it, e.g. by removing quotes, that'll stop working. They can represent all fields as quoted strings, because protobuf knows what the field type is from its own .proto schema file that was used to generate the code in the first place.

    Perhaps you're looking to re-use such JSON data in another way, without the benefit of protobuf autogenerated code? If so, this encoder is not appropriate for your purpose. However, doing so rather defeats the point of using something like Protobufs in the first place.

    The whole idea of protobufs (and other things like it) is that you use protobufs and protobuf-generated code exclusively. It's there to support efficient implementation of systems with intra-system heterogenity (you can use lots of different languages) without having to muck around deciding how bits of the system are going to exchange data with each other. You use the one .proto file for code generation across the entire system, and then details like "are field quoted strings or not?" become of no concern, and (really) the details of the wire format should be considered opaque, not something you need to know about. Generally, before adopting a serialisation standard such as protobuf, one should ensure that it supports all the languages and environments into / out of which your data needs to pass, otherwise you run into situations where you then can't easily consume data in one part of a project. Protobuf is widely supported, so it's a pretty good bet, but it does not support every lanuage on every platform. I note that the official documentation doesn't really mention Javascript anywhere.

    If for some reason you can't use protobuf generated code in part of the project, well that makes life a bit more difficult. You'd have to hand-spin an intermediate parser to convert from Google's settled standard on what the JSON should look like and whatever else you need it to be.