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 Decoder
s, 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 Decoder
s, otherwise it will try to parse Base64 string as a list of ints, resulting in a failure.
您还需要为Array[Byte]构建一个解码器,并为解码器重复上面的过程,否则它将尝试将Base64字符串解析为一个ints列表,从而导致失败。