2015-06-16 26 views
7

Mam następującej konfiguracji:dostarczaniu wartości dla pojedynczych ukrytą w grze Json biblioteki

sealed trait Status 
case object Edited extends Status 
case object NotEdited extends Status 

case class Tweet(content:String, status:Status) 

chcę użyć odtwarzania formatu JSON, więc myślę, że muszę mieć coś takiego (nie chcę robić to w obiekcie towarzysz):

trait JsonImpl{ 
    implicit val TweetFormat = Json.format[Tweet] 
    implicit val statusFormat = Json.format[Status] 
    implicit val StatusFormat = Json.format[Edited.type] 
    implicit val NotEditedFormat = Json.format[NotEdited.type] 
} 

ale kompilator narzeka i mówi:

No implicit format for Tweet available.

Mówi się również, że nie można używać Edited.type, ponieważ wymaga zastosowania i anulowania funkcji. Co powinienem zrobić?

Edit1:

mogę myśleć o coś takiego:

implicit object StatusFormat extends Format[Status] { 
    def reads(json: JsValue) = 
     (json \ "type").get.as[String] match { 
     case "" => Edited 
     case _ => UnEdited 
     } 

    def writes(stat: Status) = JsObject(Seq(
     stat match { 
     case Edited => "type" -> JsString("Edited") 
     case NotEdited => "type" -> JsString("UnEdited") 
     } 
    )) 
    } 

ale read część ma problemu, kompilator narzeka, że ​​musi JsonResult nie Edited.type

Odpowiedz

2

Dla robi, że powinienem zdefiniuj niejawny obiekt podobny do tego:

implicit object StatusFormat extends Format[Status] { 
    def reads(json: JsValue) = 
     json match { 
     case JsString("Edited") => JsSuccess(Edited) 
     case JsString("NotEdited") => JsSuccess(NotEdited) 
     case _ => JsError("cannot parse it") 
     } 

    def writes(stat: Status) = JsString(stat.toString) 
} 
6

Jest również możliwe, aby to zrobić dość gładko z API funkcjonalnej:

import play.api.data.validation.ValidationError 
import play.api.libs.functional.syntax._ 
import play.api.libs.json._ 

implicit val StatusFormat: Format[Status] = Format(
    (__ \ 'type).read[String].collect[Status](ValidationError("Unknown status")) { 
    case "UnEdited" => NotEdited 
    case "Edited" => Edited 
    }, 
    (__ \ 'type).write[String].contramap { 
    case Edited => "Edited" 
    case NotEdited => "UnEdited" 
    } 
) 

implicit val TweetFormat: Format[Tweet] = Json.format[Tweet] 

Uważam to wyraźniej niż wdrożenie reads i writes metod ręcznie, głównie dlatego, że zwraca uwagę na symetrię pomiędzy kodowania i dekodowania. To kwestia gustu.

+0

to "__" naprawdę dwa podkreślenia (tyle symboli do zapamiętania :))? gdzie jest symetria? (spróbuj nauczyć się wyglądać "funkcjonalnie" w dzisiejszych czasach, czy polecasz http://www.manning.com/bjarnason/ czy coś lepszego?) – Omid

+0

Tak, to naprawdę '__'. Możesz napisać 'JsPath', jeśli ci się nie podoba. Jestem też sceptyczny wobec ciężkich bibliotek operatora, ale Play JSON ma tylko kilku operatorów i myślę, że są całkiem rozsądni. –