2016-07-01 12 views
1

を持っている「スマートコンストラクタ」とPersonクラスを考えると、すなわちPerson#buildで唯一の「有効」値はPersonを構築します読み込み:の定義は、[X] Xは、プライベートコンストラクタ

case class Person private(age: Int) 

object Person { 
    def build(age: Int): Option[Person] = 
    if (age >= 0 && age <= 125) Some(Person(age)) else None  
} 

私は入れてReads[Person]を作成しましたPersonのコンパニオンオブジェクトへのそれ:

import play.api.libs.json._ 
import play.api.libs.functional.syntax._ 

    implicit val reads: Reads[Person] = 
    (__ \ 'age).read[Int].map(a => 
    Person.build(a).getOrElse(throw new RuntimeException("invalid age")    
    ) 

は、より良い方法はありますか?可能であれば例外を避けることを好むだろう。あなたがプレイ機能的なスタイルを落とすために喜んでいる場合

+0

なぜあなたはPersonクラス(age:Int){require(age> = 0 && age <= 125、 "invalid age")}を使用しませんか? – Simon

+0

例外を回避する、つまり例外を超えてMonadsを使用する –

+0

コンパニオンオブジェクトでの読み取りの定義はどうでしょうか? – pedrofurla

答えて

2

あなたはJsResultモナドを利用することができます:

new Format[Person] { 
    override def writes(o: Person): JsValue = ??? 

    override def reads(json: JsValue): JsResult[Person] = { 
    try{ 
     json.as[JsObject].value.get("age") 
     .flatMap(age => Person.build(age.as[Int])).map(JsSuccess(_)) 
     .getOrElse(JsError("wrong age")) 
    } catch { 
     case e: Exception => 
     JsError("wrong age") 
    } 
    } 
} 

val person = Json.toJson(Person.build(30)) 

val parsed: \/[String, Person] = person.validate[Person].map(\/-(_)).getOrElse(-\/("some bad request")) 

だから、私は私のコメントで提案よりも少し複雑ですが、基本的に、あなたはにパースをラップすることができますメソッドは、JsSuccessを右に変換し、JsErrorを左に変換します。try/catch私は、送信されたjsonがオブジェクトではなく、値のみ、または年齢フィールドが整数でない場合を検出するために使用します。

関連する問題