2017-06-24 49 views
1

我的目标是JSON转换成以下模型:瑟茜:用不同的可能的内容类型解码的容器类型

case class Container(typeId: Int, timestamp: Long, content: Content) 

sealed trait Content 
case class ContentType1(...) extends Content 
case class ContentType2(...) extends Content 
case class ContentType3(...) extends Content 
  • 有一个容器类型,其结构总是看起来是一样的。
  • 容器的content由看起来完全不同的类型表示(关于属性的数量和类型)。但是,所有的内容类型在编译时都是已知的,并且实现了一个密封的特性。
  • 容器的typeId属性指示内容类型。例如。值为N意味着content的类型为ContentTypeN等等。
  • JSON结构看起来完全像您期望的那样,并直接映射到上面显示的Scala类型。
  • (顺便说一句:我打开更改容器类型为Container[A <: Content],如果这是一个更优雅的解决方案)。

什么是一个很好的方法来解码与circe?我猜在这种情况下自动解码不起作用。

编辑:所述JSON结构的文档中描述了内容字段作为?mixed (object, integer, bool),所以它也可以是一个简单IntBoolean代替的情况下的类对象。但现在可以忽略这两种类型(尽管为此提供解决方案会很好)。

回答

0

我会使用semiauto(与deriveDecoder),validateor

case class Container[+C](typeId: Int, timestamp: Long, content: C) 

sealed trait Content 
@JsonCodec case class ContentType1(...) extends Content 
@JsonCodec case class ContentType2(...) extends Content 

object Content { 
    import shapeless._ 
    import io.circe._ 
    import io.circe.generic.semiauto._ 

    def decodeContentWithGuard[T: Decoder](number: Int): Decoder[Content[T]] = { 
    deriveDecoder[Content[T]].validate(_.downField("typeId") == Right(number), s"wrong type number, expected $number") 
    } 

    implicit val contentDecoder: Decoder[Container[Content]] = { 
    decodeWithGuard[ContentType1](1) or 
    decodeWithGuard[ContentType2](2) 
    } 
} 

如果你不想协注解,你必须映射和上溯造型内ContentTypeXContent

可能还有一个没有通用的解决方案,但是你不能使用半自动。

可能不会编译,没有测试它。