2016-04-08 22 views
2

varsayalım ben yazabilirim play-json böyle jsonDecode tek alan

{ 
    "sha": "some sha", 
    "parents": [{ 
    "url": "some url", 
    "sha": "some parent sha" 
    }] 
} 

ve bu tür vaka sınıf

case class Commit(sha: String, parentShas: List[String]) 

böyle okur var : Ben argonaut/circe içinde çözme "ebeveyn" tek "sha" bir eşdeğer yol arıyorum ama herhangi bulamadı

val commitReads: Reads[Commit] = (
    (JsPath \ "sha").read[String] and 
    (JsPath \ "parents" \\ "sha").read[List[String]] 
)(Commit.apply _) 

. "HCursor/ACursor" aşağıArray var ama oradan ne yapacağımı bilmiyorum. Şimdiden çok teşekkür ederim!

cevap

2

Ne circe ne de Argonaut hangi alanların JSON nesnesinde okunduğunu izler, bu nedenle fazladan "url" alanını (Play'da olduğu gibi) görmezden gelebilirsiniz. Trickier parçası, şu anda sahip olmadığınız Play'in \\ eşdeğerini buluyor, ancak beni eklemeniz gerektiğine ikna oldunuz. Sonra

import cats.syntax.cartesian._ 

implicit val decodeCommit: Decoder[Commit] = 
    (Decoder[Sha] |@| Decoder.instance(_.get[List[Sha]]("parents"))).map(Commit(_, _)) 

Ve:

scala> import io.circe.jawn._ 
import io.circe.jawn._ 

scala> decode[Commit](doc) 
res0: cats.data.Xor[io.circe.Error,Commit] = Right(Commit(Sha(some sha),List(Sha(some parent sha)))) 
Cats uygulamalı sözdizimi kullanarak,

import io.circe.Decoder 

val doc = """ 
{ 
    "sha": "some sha", 
    "parents": [{ 
    "url": "some url", 
    "sha": "some parent sha" 
    }] 
} 
""" 

case class Sha(value: String) 

object Sha { 
    implicit val decodeSha: Decoder[Sha] = Decoder.instance(_.get[String]("sha")).map(Sha(_)) 
} 

case class Commit(sha: Sha, parentShas: List[Sha]) 

object Commit { 
    implicit val decodeCommit: Decoder[Commit] = for { 
    sha <- Decoder[Sha] 
    parents <- Decoder.instance(_.get[List[Sha]]("parents")) 
    } yield Commit(sha, parents) 
} 

Veya: Eğer ayrı SHA türü varsa hepsinden

Birincisi, bu nispeten kolaydır

Ama bu gerçekten bir cevap değil, çünkü modelinizi değiştirmenizi istemiyorum. gerçekçi cevap :) biraz daha az eğlenceli:

case class Commit(sha: String, parentShas: List[String]) 

object Commit { 
    val extractSha: Decoder[String] = Decoder.instance(_.get[String]("sha")) 

    implicit val decodeCommit: Decoder[Commit] = for { 
    sha <- extractSha 
    parents <- Decoder.instance(c => 
     c.get("parents")(Decoder.decodeCanBuildFrom[String, List](extractSha, implicitly)) 
    ) 
    } yield Commit(sha, parents) 
} 

Bu kötü ve Eğer gerekli olduğunu utanıyorum ama işe yarıyor. Gelecekte bir serbest bırakma sürümünün daha iyi hale geldiğinden emin olmak için sadece an issue başvurdum.

İlgili konular