json - Circe 编码密封特征和 Co 产品案例类失败
问题描述
我有以下案例类:
case class SmartMeterData(
dateInterval: SmartMeterDataInterval = HalfHourInterval(),
powerUnit: PowerUnit = KWH,
smartMeterId: String,
timestamp: String,
value: Double
) {
def timeIntervalInDuration: FiniteDuration = dateInterval match {
case HalfHourInterval(_) => FiniteDuration(30, TimeUnit.MINUTES)
case FullHourInterval(_) => FiniteDuration(60, TimeUnit.MINUTES)
}
}
object SmartMeterData {
sealed trait SmartMeterDataInterval { def interval: String }
case class HalfHourInterval(interval: String = "HH") extends SmartMeterDataInterval
case class FullHourInterval(interval: String = "FH") extends SmartMeterDataInterval
sealed trait PowerUnit
case object WH extends PowerUnit
case object KWH extends PowerUnit
case object MWH extends PowerUnit
}
我刚刚写了一个非常简单的单元测试,看看 Circe 是否适用于我的场景:
"SmartMeterData" should "successfully parse from a valid JSON AST" in {
val js: String = """
{
"dateInterval" : "HH",
"powerUnit" : "KWH",
"smartMeterId" : "LCID-001-X-54",
"timestamp" : "2012-10-12 00:30:00.0000000",
"value" : 23.0
}
"""
val expectedSmartMeterData = SmartMeterData(smartMeterId = "LCID-001-X-54", timestamp = "2012-10-12 00:30:00.0000000", value = 23.0)
decode[SmartMeterData](js) match {
case Left(err) => fail(s"Error when parsing valid JSON ${err.toString}")
case Right(actualSmartMeterData) =>
assert(actualSmartMeterData equals expectedSmartMeterData)
}
}
但它失败并出现以下错误:
Error when parsing valid JSON DecodingFailure(CNil, List(DownField(dateInterval)))
circe 是否有一个已知的限制,它还不适用于我上面的案例?
解决方案
Circe 没有理由不工作,但是按照您设计数据模型的方式,任何 Scala JSON 库可以自动生成编码器/解码器的可能性基本上为零,而无需大量手动工作。
例如
sealed trait SmartMeterDataInterval { def interval: String }
case class HalfHourInterval(interval: String = "HH") extends SmartMeterDataInterval
case class FullHourInterval(interval: String = "FH") extends SmartMeterDataInterval
在任何自动为 es 派生实例的 Scala JSON 库中,两者的模式都case class
将遵循
{ "interval": "HH" }
对于HalfHourInterval
和
{ "interval": "FH" }
for FullHourInterval
(即因为每个都有一个名为 的字符串字段interval
,所以它们实际上是同一个类)。实际上,您的模型允许您拥有FullHourInterval("HH")
,对于为 circe 中的 ADT 层次结构生成解码器的至少一种方法(文档中使用 shapeless 的方法)将是解码的结果{ "interval": "HH" }
,因为这基本上需要第一个构造函数匹配的词汇顺序(即FullHourInterval
)。如果目的是只允许整小时或半小时的间隔,那么我建议将其表达为:
case object HalfHourInterval extends SmartMeterDataInterval { def interval: String = "HH" }
case object FullHourInterval extends SmartMeterDataInterval { def interval: String = "FH" }
我并不直接熟悉 circe 如何对case object
s 进行编码,但您可以很容易地为 s 定义编码器和解码器SmartMeterDataInterval
:
object SmartMeterDataInterval {
implicit val encoder: Encoder[SmartMeterDataInterval] =
Encoder.encodeString.contramap[SmartMeterDataInterval](_.interval)
implicit val decoder: Decoder[SmartMeterDataInterval] =
Decoder.decodeString.emap {
case "HH" => Right(HalfHourInterval)
case "FH" => Right(FullHourInterval)
case _ => Left("not a valid SmartMeterDataInterval")
}
}
然后,您将执行类似的操作来定义Encoder
/ Decoder
forPowerUnit
推荐阅读
- c# - 无法创建跨平台 ARCore 会话 (ErrorInvalidArgument)。GoogleARCoreInternal.ARCoreIOSLifecycleManager:EnableSession()
- javascript - 使用(引导)HTML 和纯 Javascript 创建待办事项列表
- c - 为什么 for 循环终止但其中的 memcpy 复制相同的子字符串?
- laravel - 在laravel中使用数组过滤集合
- c# - 我的 for 循环正在减慢我的计时器。怎么修?
- numpy - 对图像列表执行平均减法?
- c++ - 自然算术 C++ 总是返回 1
- java - 在 Try Catch 中从 Scanner 将整数解析为字符串
- java - xpath在java中不起作用
- javascript - 反应:如何过滤道具中的对象数组