2016-02-26 2 views
3

Я пытаюсь разобрать JSON какДекодирования в рекурсивный АТД с Аргонавт

{ 
    "element": "string", 
    "content": "application/json" 
} 

где element решает, какой тип является JSON. Но мой код не разбирается.

http://scastie.org/15213

import scalaz._, Scalaz._ 
import argonaut._, Argonaut._, Shapeless._ 

case class ArrayAttributes(default: List[StringElement]) 

sealed trait Element 
case class StringElement(content: String) extends Element 
case class ArrayElement(attributes: ArrayAttributes, content: List[Element]) extends Element 
case class Reference(element: String) extends Element { def content = element } 

object Parser { 

    def kindDecode[T](
    kinds: Map[String, DecodeJson[T]], 
    fail: HCursor => DecodeResult[T] = { c: HCursor => DecodeResult.fail[T]("expected one of ${kind.keys}", c.history) }): DecodeJson[T] = DecodeJson(c => 
    (c --\ "element").as[String].flatMap { kind => 
     kinds.get(kind).map(_.decode(c)).getOrElse(fail(c)) 
    } 
) 

    implicit def elementDecode: DecodeJson[Element] = kindDecode(
    Map(
     "string" -> DecodeJson.of[StringElement].map(identity[Element]), 
     "array" -> arrayDecode.map(identity[Element]) 
    ), 
    { c => DecodeJson.of[Reference].decode(c).map(identity[Element]) } 
) 

    def arrayDecode: DecodeJson[ArrayElement] = jdecode2L(ArrayElement.apply)("attributes", "content") 

} 

ответ

1

Я собираюсь ответить с текущей вехой Аргонавтов-бесформенным (1.0.0-M1), которая имела соответствующие дополнения начиная с версии 0.3.1.

Он позволяет указать так называемые JsonSumCodec s для типов сумм, которые управляют тем, как подтипы кодируются/различаются.

Определяя один для Element в его объекте компаньона, как

implicit val jsonSumCodecForElement = derive.JsonSumCodecFor[Element](
    derive.JsonSumTypeFieldCodec(
    typeField = "element", 
    toTypeValue = Some(_.stripSuffix("Element").toLowerCase) 
) 
) 

вашего пример просто работает:

> Parse.decodeEither[Element](member) 
res1: (String \/ (String, CursorHistory)) \/ Element = 
    \/-(StringElement(application/json)) 

JsonSumCodecFor выше класс типа, который обеспечивает JsonSumCodec для данного типа, здесь Element. Как JsonSumCodec, мы выбираем JsonSumTypeFieldCodec, который по умолчанию использует поле "type", чтобы различать подтипы. Здесь мы выбираем "element" вместо "type", а также преобразуем имена подтипов (аргумент toTypeValue), чтобы они соответствовали именам ввода примера.

+0

Подробный пример см. В этом scastie: http://scastie.org/15217 – al3xar

Смежные вопросы