ScalaPB and JSON

ScalaPB can convert protocol buffers to and from JSON, using json4s.

Setting up your project

Make sure that you are using ScalaPB 0.5.x or later.

In build.sbt add a dependency on scalapb-json4s:

// For ScalaPB 0.7.x:
libraryDependencies += "com.thesamet.scalapb" %% "scalapb-json4s" % "0.7.0"

// For ScalaPB 0.6.x (note the different groupId):
libraryDependencies += "com.trueaccord.scalapb" %% "scalapb-json4s" % "0.3.2"

// For ScalaPB 0.5.x (note the different groupId):
libraryDependencies += "com.trueaccord.scalapb" %% "scalapb-json4s" % "0.1.6"

In your code, you can now convert to JSON:

import scalapb.json4s.JsonFormat

val r: String = JsonFormat.toJsonString(myProto)

Parse JSON back to a protocol buffer:

import scalapb.json4s.JsonFormat

val proto: MyProto = JsonFormat.fromJsonString[MyProto](
    """{"x": "17"}""")

There are lower-level functions toJson() and fromJson() that convert from protos to json4s’s JValue:

def toJson(m: GeneratedMessage): JObject

def fromJson[Proto](value: JValue): Proto

Finally, in JsonFormat there are two implicit methods that instantiate Reader[Proto] and Writer[Proto].

More printing and parsing options

There are a few more options available to customize the format used to print and parse JSON. To take advantage of that, instantiate Printer and Parser and call toJson() / fromJson() as usual.

For example:

new scalapb.json4s.Printer(
  includingDefaultValueFields = true,
  preservingProtoFieldNames = true,
  formattingLongAsNumber = true
).toJson(myProto)

Options:

  • includingDefaultValueFields (default: false): should fields that are set to their default value be included in the output.
  • preservingProtoFileNames (default: false): by default, field names are mapped to lowerCamelCase and become JSON object keys. Setting this option to true would make the parser and the printer use the original field names as specified in the proto file (normally, in snake_case)
  • formatLongAsNumber (default: false): by default, longs are serialized as strings. To use the numeric representation, set this option to true. Note that due to the way Javascript represents numbers, there is a possibility to lose precision (more details here).

See the list of constructor paramerters here

Printing and parsing Anys

In Protocol Buffers, google.protobuf.Any is a type that embeds an arbitrary protobuf message. An Any is represented as a message that contains a typeUrl field that identifies the type, and a bytes field value which contains the serialized contents of a message. In JSON, the message embedded in the Any is serialized as usual, and there is a @type key added to it to identify which message it is. The parser expects this @type key to know which message it is. To accomplish this, all the expected embedded types need to be registered with a TypeRegistry so the printer and parser know how to process the embedded message.

The following example is based on this proto.

import com.thesamet.docs.json._
import scalapb.json4s.{Printer, Parser, TypeRegistry}

val c = MyContainer(
  myAny=Some(
    com.google.protobuf.any.Any.pack(
      MyMessage(x=17)
    )
  )
)
// c: MyContainer = MyContainer(
//   Some(
//     Any(
//       "type.googleapis.com/com.thesamet.docs.MyMessage",
//       <ByteString@69e95b47 size=2>
//     )
//   )
// )

val typeRegistry = TypeRegistry().addMessage[MyMessage]
// typeRegistry: TypeRegistry = TypeRegistry(
//   Map(
//     "type.googleapis.com/com.thesamet.docs.MyMessage" -> com.thesamet.docs.json.MyMessage$@4517a5f
//   ),
//   Set()
// )

val printer = new Printer().withTypeRegistry(typeRegistry)
// printer: Printer = scalapb.json4s.Printer@17e69356

printer.print(c)
// res0: String = "{\"myAny\":{\"@type\":\"type.googleapis.com/com.thesamet.docs.MyMessage\",\"x\":17}}"

Conversely, you can start from a JSON and parse it back to a MyContainer that contains an Any field:

val parser = new Parser().withTypeRegistry(typeRegistry)
// parser: Parser = scalapb.json4s.Parser@2793412a

parser.fromJsonString[MyContainer]("""
  {
    "myAny": {
      "@type": "type.googleapis.com/com.thesamet.docs.MyMessage",
      "x": 17
    }
  }""")
// res1: MyContainer = MyContainer(
//   Some(
//     Any(
//       "type.googleapis.com/com.thesamet.docs.MyMessage",
//       <ByteString@1df0e660 size=2>
//     )
//   )
// )

转载于:https://my.oschina.net/u/2391658/blog/3069574

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值