JSON/Protobuf converters for ScalaPB using jsoniter-scala.
The structure of this project is hugely inspired by scalapb-circe and scalapb-json4s.
Include in your build.sbt file
libraryDependencies += "io.github.hoangmaihuy" %% "scalapb-jsoniter" % "0.1.0"For Scala.js or Scala Native
libraryDependencies += "io.github.hoangmaihuy" %%% "scalapb-jsoniter" % "0.1.0"libraryDependencies += "io.github.hoangmaihuy" %% "scalapb-jsoniter-macros" % "0.1.0"There are two functions you can use directly to serialize/deserialize your messages:
import scalapb_jsoniter.JsonFormat
JsonFormat.toJsonString(msg) // returns String
JsonFormat.fromJsonString[MyMessage](str) // returns MyMessageFor more control, create Printer and Parser instances with custom settings:
import scalapb_jsoniter.{Printer, Parser}
val printer = new Printer(
includingDefaultValueFields = true,
preservingProtoFieldNames = true,
formattingLongAsNumber = true,
formattingEnumsAsNumber = true,
formattingMapEntriesAsKeyValuePairs = true
)
printer.print(msg) // returns Stringval parser = new Parser(
preservingProtoFieldNames = true,
mapEntriesAsKeyValuePairs = true
)
parser.fromJsonString[MyMessage](str) // returns MyMessageYou can also write/read directly to jsoniter-scala's JsonWriter/JsonReader:
import com.github.plokhotnyuk.jsoniter_scala.core.*
import scalapb_jsoniter.{Printer, Parser}
val printer = new Printer()
val parser = new Parser()
// Write to JsonWriter
printer.toJson(msg, out)
// Read from JsonReader
parser.fromJson[MyMessage](in)Import codecs to get implicit JsonValueCodec instances for any GeneratedMessage or GeneratedEnum:
import com.github.plokhotnyuk.jsoniter_scala.core.*
import scalapb_jsoniter.codec.*
writeToString(Guitar(42)) // returns {"numberOfStrings":42}
readFromString[Guitar]("""{"numberOfStrings": 42}""") // returns Guitar(42)You can define an implicit Printer and/or Parser to control printing and parsing settings.
For example, to include default values in JSON:
import com.github.plokhotnyuk.jsoniter_scala.core.*
import scalapb_jsoniter.codec.*
import scalapb_jsoniter.Printer
implicit val p: Printer = new Printer(includingDefaultValueFields = true)
writeToString(Guitar(0)) // returns {"numberOfStrings":0}The scalapb-jsoniter-macros module provides compile-time validation and convenience methods.
Parse Struct and Value literals at compile time:
import scalapb_jsoniter.ProtoMacrosJsoniter.*
val s = struct"""{"key": "value"}""" // google.protobuf.Struct, validated at compile time
val v = value"""42""" // google.protobuf.Value, validated at compile timeValidate JSON against a protobuf message schema at compile time:
import scalapb_jsoniter.ProtoMacrosJsoniter.*
val msg = MyMessage.fromJsonConstant("""{"field": "value"}""") // compile error if JSON is invalidParse JSON strings via message companions with various return types:
import scalapb_jsoniter.ProtoMacrosJsoniter.*
MyMessage.fromJson(jsonStr) // returns MyMessage (throws on error)
MyMessage.fromJsonOpt(jsonStr) // returns Option[MyMessage]
MyMessage.fromJsonEither(jsonStr) // returns Either[Throwable, MyMessage]
MyMessage.fromJsonTry(jsonStr) // returns Try[MyMessage]To serialize/deserialize google.protobuf.Any messages, register the relevant message companions in a TypeRegistry:
import scalapb_json.TypeRegistry
import scalapb_jsoniter.{Printer, Parser}
val typeRegistry = TypeRegistry.empty
.addMessageByCompanion(MyMessage.companion)
val printer = new Printer(typeRegistry = typeRegistry)
val parser = new Parser(typeRegistry = typeRegistry)All standard protobuf types are supported, including well-known types:
- Primitive types (int32, int64, uint32, uint64, float, double, bool, string, bytes)
- Enums
- Nested messages
- Repeated fields and maps
- Oneof fields
google.protobuf.Timestampgoogle.protobuf.Durationgoogle.protobuf.FieldMaskgoogle.protobuf.Struct,Value,ListValuegoogle.protobuf.Any- Wrapper types (
DoubleValue,FloatValue,Int32Value,Int64Value,UInt32Value,UInt64Value,BoolValue,StringValue,BytesValue)