Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

provide convenient user-api to manually create codecs #553

Open
domdorn opened this issue Jan 26, 2022 · 0 comments
Open

provide convenient user-api to manually create codecs #553

domdorn opened this issue Jan 26, 2022 · 0 comments

Comments

@domdorn
Copy link

domdorn commented Jan 26, 2022

Quite often I find myself in the need to manually create a codec for a certain data type or multiple different codecs for a single type.
For example, in one of our services we have a java.lang.enum that holds physical units from timeseries databases. This unit gets delivered by a 3rd-party system as e.g. "EUR/MWh" and we convert it to our UnitsEnum.EUR_PRO_MEGAWATTSTUNDE value

The enum type is used in the data classes that interact with the 3rd-party system, as well in the responses given out by our services. We do not want to have two enums containing the same information and map between them.

In Jsoniter-Scala this is straightforward, we simply created two codecs by hand with minimal boilerplate. Something similar should be possible with zio-json

  val unitWebCodec: JsonValueCodec[UnitEnum] = new JsonValueCodec[UnitEnum] {
    override def decodeValue(in: JsonReader, default: UnitEnum): UnitEnum =
      UnitEnum.valueOf(in.readString("KEINE"))

    override def encodeValue(x: UnitEnum, out: JsonWriter): Unit = out.writeVal(x.name())

    override def nullValue: UnitEnum = UnitEnum.KEINE
  }

  val unitClientCodec: JsonValueCodec[UnitEnum] = new JsonValueCodec[UnitEnum] {
    override def decodeValue(in: JsonReader, default: UnitEnum): UnitEnum =
      UnitEnum.getFromCode(in.readString("none"))

    override def encodeValue(x: UnitEnum, out: JsonWriter): Unit = out.writeVal(x.getCode)

    override def nullValue: UnitEnum = UnitEnum.KEINE
  }

Dependening if we're in the layer interacting with the 3rd-party service or in the layer serving our web-responses, we simply define one of these two codecs as implicit and the macros generating the responses pick them up, e.g.

object ThirdPartyClientJsoniterSupport {
... 
  implicit val UnitCodec: JsonValueCodec[UnitEnum] = unitClientCodec
}
object MyWebController { 
 case class Response(..., unit: UnitEnum, ...) 

implicit val UnitCodec: JsonValueCodec[UnitEnum]              = unitWebCodec
implicit val RequestJsonCodec: JsonValueCodec[Request] = JsonCodecMaker.make[Request]
implicit val ResponseJsonCodec: JsonValueCodec[Response] = JsonCodecMaker.make[Response](
  CodecMakerConfig
    .withTransientEmpty(false)
    .withTransientNone(false)
    .withTransientDefault(false))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant