如何覆盖circe中的默认编解码器?

时间:2021-07-24 23:10:35

I'd like to encode Array[Byte] fields of my case classes as Base64 strings. For some reason Circe doesn't pick up my codec using default one instead that converts byte array into json array of ints.

我想将case类的数组[Byte]字段编码为Base64字符串。由于某种原因,Circe并没有使用默认的编码,而是将字节数组转换成ints的json数组。

What should I do to fix it ? Here is my minimized code

我该怎么做才能修好它?这是我的最小化代码

import io.circe.generic.JsonCodec

sealed trait DocumentAttribute

@JsonCodec
sealed case class DAAudio(title: Option[String], performer: Option[String], waveform: Option[Array[Byte]], duration: Int) extends DocumentAttribute

@JsonCodec
sealed case class DAFilename(fileName: String) extends DocumentAttribute

object CirceEncodersDecoders {
  import io.circe._
  import io.circe.generic.extras._
  import io.circe.generic.extras.semiauto._

  implicit val arrayByteEncoder: Encoder[Array[Byte]] = Encoder.encodeString.contramap[Array[Byte]] { bytes ⇒
    Base64.getEncoder.encodeToString(bytes)
  }

  val printer: Printer = Printer.noSpaces.copy(dropNullValues = true, reuseWriters = true)
  implicit val config: Configuration = Configuration.default.withDiscriminator("kind").withSnakeCaseConstructorNames.withSnakeCaseMemberNames

  implicit val DocumentAttributeEncoder: Encoder[DocumentAttribute] = deriveEncoder
  implicit val DocumentAttributeDecoder: Decoder[DocumentAttribute] = deriveDecoder
}

object main {
  def main(args: Array[String]): Unit = {
    import CirceEncodersDecoders._

    import io.circe.parser._
    import io.circe.syntax._

    val attributes: List[DocumentAttribute] = List(
      DAAudio(Some("title"), Some("perform"), Some(List(1, 2, 3, 4, 5).map(_.toByte).toArray), 15),
      DAFilename("filename")
    )
    val j2 = attributes.asJson
    val decoded2 = decode[List[DocumentAttribute]](j2.noSpaces)
    println(decoded2)
  }
}

1 个解决方案

#1


1  

When you do this:

当你这样做:

implicit val DocumentAttributeEncoder: Encoder[DocumentAttribute] = deriveEncoder

circe tries to get suitable Encoder for DAFilename and DAAudio. However, since those already exist (by means of @JsonCodec on individual classes), it does not re-derive them from scratch using generics and your Encoder[Array[Byte]] at scope - which you want.

circe试图为DAFilename和DAAudio找到合适的编码器。但是,由于它们已经存在(通过在单个类上使用@JsonCodec),它不会在作用域中使用泛型和编码器[Array[Byte]]重新派生它们——这是您想要的。

So you can either get rid of @JsonCodec (so it auto-derives codecs for DAFilename and DAAudio together with DocumentAttribute) or trigger re-derivation manually:

因此,您可以删除@JsonCodec(这样它就可以自动获取DAFilename和DAAudio的codecs以及DocumentAttribute),或者手动触发重新派生:

implicit val AudioDecoder: Encoder[DAAudio] = deriveEncoder // takes priority over existing one
implicit val DocumentAttributeEncoder: Encoder[DocumentAttribute] = deriveEncoder // AudioDecoder will be used here

You also need to build a Decoder for Array[Byte] and repeat the process above for Decoders, otherwise it will try to parse Base64 string as a list of ints, resulting in a failure.

您还需要为Array[Byte]构建一个解码器,并为解码器重复上面的过程,否则它将尝试将Base64字符串解析为一个ints列表,从而导致失败。

#1


1  

When you do this:

当你这样做:

implicit val DocumentAttributeEncoder: Encoder[DocumentAttribute] = deriveEncoder

circe tries to get suitable Encoder for DAFilename and DAAudio. However, since those already exist (by means of @JsonCodec on individual classes), it does not re-derive them from scratch using generics and your Encoder[Array[Byte]] at scope - which you want.

circe试图为DAFilename和DAAudio找到合适的编码器。但是,由于它们已经存在(通过在单个类上使用@JsonCodec),它不会在作用域中使用泛型和编码器[Array[Byte]]重新派生它们——这是您想要的。

So you can either get rid of @JsonCodec (so it auto-derives codecs for DAFilename and DAAudio together with DocumentAttribute) or trigger re-derivation manually:

因此,您可以删除@JsonCodec(这样它就可以自动获取DAFilename和DAAudio的codecs以及DocumentAttribute),或者手动触发重新派生:

implicit val AudioDecoder: Encoder[DAAudio] = deriveEncoder // takes priority over existing one
implicit val DocumentAttributeEncoder: Encoder[DocumentAttribute] = deriveEncoder // AudioDecoder will be used here

You also need to build a Decoder for Array[Byte] and repeat the process above for Decoders, otherwise it will try to parse Base64 string as a list of ints, resulting in a failure.

您还需要为Array[Byte]构建一个解码器,并为解码器重复上面的过程,否则它将尝试将Base64字符串解析为一个ints列表,从而导致失败。