2017-11-03 4 views
1

リクエストからJSON文字列を読み込み、Play/ScalaベースのRESTアプリケーションでケースクラスに変換しようとしています。 私のコードはJSON/BigInt Jsonデシリアライザ(再生/スカラ)

implicit val memberRead: Reads[MemberInfo] = (
(JsPath \ "memberId").readNullable[BigInt] and 
    (JsPath \ "firstName").read[String] and 
    (JsPath \ "lastName").read[String] and 
    (JsPath \ "janrainUUID").readNullable[String] and 
    (JsPath \ "phones").read[Seq[MemberPhone]] and 
    (JsPath \ "address").read[Seq[MemberAddress]] 
)(MemberInfo.apply _) 

implicit val addressRead: Reads[MemberAddress] = (
(JsPath \ "addressId").readNullable[BigInt] and 
    (JsPath \ "addressType").read[String] and 
    (JsPath \ "address").read[String] and 
    (JsPath \ "memberId").read[BigInt] 
)(MemberAddress.apply _) 

implicit val phoneRead: Reads[MemberPhone] = (
(JsPath \ "phoneId").readNullable[BigInt] and 
    (JsPath \ "phoneNumber").read[String] and 
    (JsPath \ "phoneType").read[String] and 
    (JsPath \ "primaryInd").read[String] and 
    (JsPath \ "memberId").read[BigInt] 
)(MemberPhone.apply _) 

...何かのようですが、私は(phoneReadでaddressReadとphoneidなどでmemberRead、あるAddressId内のすべての3 readNullable [BigIntの]、MEMBERIDのために)いくつかのコンパイルエラーを取得しています。エラーが...

No Json deserializer found for type BigInt. Try to implement an implicit Reads or Format for this type. 

私の場合クラスがjanrainUUIDため、このようないくつかの...

case class MemberInfo(memberId : Option[BigInt],firstName : String, lastName : String,janrainUUID :Option[String] , phones : Seq[MemberPhone],address : Seq[MemberAddress]) 
case class MemberAddress(addressId:Option[BigInt],addressType:String,address:String,memberId:BigInt) 
case class MemberPhone(phoneId : Option[BigInt], phoneNumber:String,phoneType:String,primaryInd:String,memberId:BigInt) 

ですされています。オプション[文字列]私は、コンパイル・エラーを取得していないのですが、BigInt型のために、私は取得しています"No JsonデシリアライザがBigInt型で見つかりませんでした"

BigIntでこのエラーが発生する理由は何ですか?実際にはそれらはDB操作を行うときのPK値なので、要求に応じることはありません。ジャージの@ignoreアノテーションのような演劇/スカラでそれを表現する方法はありますか?

任意の助けが理解されるであろう、おかげでたくさん...

+0

使用しているプレイバージョンを知ることはできますか? – Learner

+1

https://github.com/playframework/play-json/pull/122 – cchantep

答えて

2

プレイ-JSONはReads[BigInt]を提供していません。 Reads[BigDecimal]のみ提供しています。

implicit val bigIntReads: Reads[BigInt] = implicitly[Reads[BigDecimal]].map(_.toBigInt()) 

や遊びのReads[BigDecimal]を使用し、その結果変換::

独自01​​を書くことができますいずれか

implicit val memberRead: Reads[MemberInfo] = (
(JsPath \ "memberId").readNullable[BigDecimal].map(_.toBigInt()) and 
    ... 

編集を:上記の解決策の両方が、車輪を再発明しないという利点を持っています彼らはplay-jsonによって提供されたいくつかの十分にテストされたインフラストラクチャ上に構築されます。そのため、この質問に対して提案された他の解決方法ではなく、主にjson文字列と数字の正確な処理には効果がありません。

1

あなたはこのようFormatを実装し、暗黙のヴァルとしてあなたコンパニオンオブジェクトでそれを使用することができます。

import play.api.libs.json._ 
import play.api.libs.functional.syntax._ 
import scala.util.Try 

object BigIntFormat extends Format[BigInt] { 
    override def reads(json: JsValue): JsResult[BigInt] = json match { 
    case JsNumber(n) => Try(JsSuccess(n.toBigInt)).getOrElse { 
     JsError(JsPath() -> JsonValidationError(s"error.expected.numeric(as BigInt), but got '$json'")) 
    } 
    case JsString(s) => Try(JsSuccess(BigInt(s))).getOrElse { 
     JsError(JsPath() -> JsonValidationError(s"error.expected.string(as BigInt), but got '$json'")) 
    } 
    case _ => JsError(JsPath() -> JsonValidationError("error.expected.string")) 
    } 

    override def writes(o: BigInt): JsValue = JsString(o.toString) 
} 

case class SomethingWithBigInt(id: BigInt, str: String) 

object SomethingWithBigInt { 
    implicit val bigIntFormatter = BigIntFormat 

    implicit lazy val format: Format[SomethingWithBigInt] = ({ 
    (JsPath \ "id").format[BigInt] and 
     (JsPath \ "str").format[String] 
    })(SomethingWithBigInt.apply, unlift(SomethingWithBigInt.unapply)) 
} 
+0

これはもっと複雑です。数字が文字列ではなくjson番号で表される場合はどうなりますか? –

+0

@FredericA。、もう1つの場合を追加する必要があります。 –

3

あなたは次のようにBigIntのためのシリアライザを定義する必要があります。

implicit val BigIntWrite: Writes[BigInt] = new Writes[BigInt] { 
    override def writes(bigInt: BigInt): JsValue = JsString(bigInt.toString()) 
    } 

    implicit val BigIntRead: Reads[BigInt] = Reads { 
    case JsString(value) => JsSuccess(scala.math.BigInt(value)) 
    case JsNumber(value) => JsSuccess(value.toBigInt()) 
    case unknown => JsError(s"Invalid BigInt") 
    } 

はちょうどこのを追加しますmemberReadシリアライザの前に行って、無効なBigIntのエラー処理を追加してください。

+0

これはそれよりも複雑です。数字が文字列ではなくjson番号で表される場合はどうなりますか? @FredericA。 –

+0

。 Uは正しかった。 json番号を表すことができませんでした。 json番号をbigintに正しく非直列化できるように私の回答を更新しました。 –

+0

さて、いまだに車輪を再発明していますが、少なくともそれは既に存在するものの上に構築できるものよりも悪くありません。 –

関連する問題