我最终使用了以下代码,其工作原理与预期一样。我不能分享子功能,但它应该给出总体思路。
implicit val dynamoFormat: DynamoFormat[JsValue] = new DynamoFormat[JsValue] {
override def read(av: AttributeValue): Either[DynamoReadError, JsValue] = {
Option(av.getS).map {
fromStringAttributeValue
} orElse Option(av.getN).map { n =>
Right(JsNumber(BigDecimal.apply(n)))
} orElse Option(av.getBOOL).map { b =>
Right(JsBoolean(b))
} orElse Option(av.isNULL).map { _ =>
Right(JsNull)
} orElse Option(av.getSS).map { ss =>
Right(JsArray(ss.asScala.map(JsString.apply)))
} orElse Option(av.getNS).map { ns =>
Right(JsArray(ns.asScala.map(n => JsNumber(BigDecimal(n)))))
} orElse Option(av.getL).map { l =>
traverse(l.asScala.toList)(read).right.map(JsArray.apply)
} orElse Option(av.getM).map { m =>
traverse(m.asScala) {
case (k, v) => read(v).right.map(j => k -> j)
}.right.map(values => JsObject(values.toMap))
} getOrElse {
Left(YOUR_ERROR_HERE)
}
}
override def write(t: JsValue): AttributeValue = {
val res = new AttributeValue()
t match {
case JsNumber(n) => res.setN(n.toString())
case JsBoolean(b) => res.setBOOL(b)
case JsString(s) => res.setS(stringToAttributeValueString(s))
case a: JsArray => res.setL(a.value.map(write).asJava)
case o: JsObject => res.setM(o.value.mapValues(write).asJava)
case JsNull => res.setNULL(true)
}
res
}
}