2017-01-09 5 views
1

ich dieses Stück von Json zu dekodieren versuchen:Kann nicht dekodieren Sets in Circe

{ 
    "id" : "e07cff6a-bbf7-4bc9-b2ec-ff2ea8e46288", 
    "paper" : { 
    "title" : "Example Title", 
    "authors" : [ 
     "1bf5e911-8878-4e06-ba8e-8159aadb052c" 
    ] 
    } 
} 

Wenn es jedoch an die Sets Teil bekommen, seine ausfällt. Die Fehlermeldung ist nicht hilfreich.

DecodingFailure([A]Set[A], List()) 

Hier sind meine docoders:

implicit val paperIdDecoder: Decoder[PaperId] = Decoder.decodeString.emap[PaperId] { str ⇒ 
    Either.catchNonFatal(PaperId(str)).leftMap(_.getMessage) 
    } 

    implicit val paperAuthorDecoder: Decoder[PaperAuthor] = Decoder.decodeString.emap[PaperAuthor] { str ⇒ 
    Either.catchNonFatal(PaperAuthor(str)).leftMap(_.getMessage) 
    } 

    implicit val paperDecoder: Decoder[Paper] = { 
    for { 
     title <- Decoder.decodeString 
     authors <- Decoder.decodeSet[PaperAuthor] 
    } yield Paper(title, authors) 
    } 

    implicit val paperViewDecoder: Decoder[PublishedPaperView] = for { 
    id <- Decoder[PaperId] 
    paper <- Decoder[Paper] 
    } yield PublishedPaperView(id, paper) 

Hier sind die Fallklassen verwendet:

case class PublishedPaperView(id: PaperId, paper: Paper) 

case class PaperId(value: String) 

case class Paper(title: String, authors: Set[PaperAuthor]) 

case class PaperAuthor(value: String) 

Antwort

1

Obwohl die Fehlerbeschreibung weit davon entfernt, explikative ist, Ihr Problem zu einem falschen Zusammenhang steht Verwendung der monadischen API des Decoders: Denken Sie daran, dass ein für das Verständnis ist ein syntaktischer Zucker für map/flatMap.

Von io.circe.Decoder

/** 
    * Monadically bind a function over this [[Decoder]]. 
    */ 
    final def flatMap[B](f: A => Decoder[B]): Decoder[B] = new Decoder[B] { 
    final def apply(c: HCursor): Decoder.Result[B] = self(c).flatMap(a => f(a)(c)) 

    override def tryDecode(c: ACursor): Decoder.Result[B] = { 
     self.tryDecode(c).flatMap(a => f(a).tryDecode(c)) 
    } 

    override def decodeAccumulating(c: HCursor): AccumulatingDecoder.Result[B] = 
     self.decodeAccumulating(c).andThen(result => f(result).decodeAccumulating(c)) 
    } 

zu diesem Code Suchen Sie sehen, dass, wenn Sie einen Decoder flatMap, erhalten Sie einen neuen Decoder auf dem gleichen Cursor-Betriebs: Der Cursor ist die aktuelle Position des Parsing-Operation .

Im folgenden Code:

implicit val paperDecoder: Decoder[Paper] = { 
    for { 
     title <- Decoder.decodeString 
     authors <- Decoder.decodeSet[PaperAuthor] 
    } yield Paper(title, authors) 
    } 

Der Cursor am Anfang des Objekts zeigt sowohl, wenn Sie versuchen, Titel und Autoren zu entschlüsseln. Wenn Sie die halbautomatische oder automatische Generierung nicht verwenden und Sie nativ mit der API arbeiten, müssen Sie den Cursor wie folgt bewegen:

implicit val paperDecoder: Decoder[Paper] = Decoder.instance(cursor => Xor.right(Paper("",Set.empty))) 

    implicit val paperViewDecoder: Decoder[PublishedPaperView] = Decoder.instance(
    cursor => 
     for { 
     id <- cursor.downField("id").as[PaperId] 
     paper <- cursor.downField("paper").as[Paper] 
    } yield PublishedPaperView(id, paper) 
) 
Verwandte Themen