2016-03-24 12 views
0
プレイとスカラ座で

とスリック、私はケースクラスとして列挙国を実装しました、そして、それは文字列としてJSONへの書き込み/読みたいです。これは完全なコードです。Play Scalaでstringをenumクラスとして読み取るにはどうすればよいですか?

package models.enums 

import play.api.libs.json._ 
import slick.lifted.MappedTo 

case class Country(id: String) extends MappedTo[String] { 
    override def value: String = id 
} 

object Country { 
    val France = Country("FR") 
    val Germany = Country("DE") 

    implicit val writes = Writes[Country](
    (site: Country) => JsString(site.value) 
) 

    // this line I need help with 
    implicit val reads = Json.reads[Country] 
} 

国別の列挙型は他のモデルでも使用されています。

{ 
    "name": "Robo" 
    "country": "DE" 
} 

上記のコードは、私が欲しいものであるプレーンな文字列として列挙型を書き込みますが、私は、暗黙の読み取り部分を実装する方法を見つけ出すことはできません。 JSONは以下のようであれば、現在の読み取りにのみ動作します:

{ 
    "name": "Robo" 
    "country": { 
    "id": "DE" 
    } 
} 

私は答えは簡単であると確信している、ちょうど正しい構文を把握することはできません。

+0

をごJSONsは、フィールド宣言の間にカンマが含まれていません。 –

答えて

1
import play.api.libs.json._ 
import play.api.libs.json.Reads._ 

implicit val reads = new Reads[Country] { 
    override def reads(json: JsValue): JsResult[Country] = for { 
    id <- (json \ "country").validate[String] 
    } yield Country(id) 
} 

(json \ "country").validate[String]次いでJsResult[Country]

又は

import play.api.libs.json._ 
import play.api.libs.json.Reads._ 

implicit val reads = new Reads[Country] { 
    override def reads(json: JsValue): JsResult[Country] = 
    (json \ "country").validate[String].map(Country(_)) 

又は

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

implicit val reads: Reads[Country] = (__ \ "country").reads[String].map(Country(_)) 
に( yield介して)マッピングされる JsResult[String]を返します

EDIT:検証上のあなたのコメントについては

、私はちょうどあなたのケースクラスではなく、JSONパーサーにそれを追加したい:

case class Country(id: String) extends MappedTo[String] { 
    private val validIds = Set(France, Germany).map(_.id) 

    require(validIds contains id, s"id must be one of $validIds") 

    override def value: String = id 
} 

トリックはステートメントを使用すると、本体内に置くということですあなたのクラスはコンストラクタの一部になります。誰が許可IDのリストにないIDでCountryを作成しようとした場合requireコールは、例外がスローされます。

+0

ありがとう、ほぼそこにトン。値が定義された "enum"、つまりDEまたはFRの1つだけであることを保証する方法はありますか?現在、文字列がUKの場合、コードで許可されます。 – Robo

+0

@Robo私はそのための解決策を追加しました。 –

0

私は密閉されたクラスを使用することをお勧めします。パターンマッチのセレクタが密封クラスのインスタンスである場合、パターンマッチングのコンパイルは、与えられたパターンセットが網羅的ではないことを診断する警告を出すことができる。即ち、実行時にMatchErrorが発生する可能性がある。私のプロジェクトから

例:

import com.pellucid.sealerate 
import play.api.libs.json._ 

sealed abstract class TokenKind(val value: String) 

object TokenKind { 

    case object PasswordReset extends TokenKind("passwordReset") 
    case object AccountConfirmation extends TokenKind("accountConfirmation") 

    def values: Set[TokenKind] = sealerate.values[TokenKind] 

    def apply(value: String): TokenKind = values.find(_.value == value).getOrElse(throw new RuntimeException(s"Can't construct TokenKind from: $value")) 

    implicit def tokenKindWrites = new Writes[TokenKind] { 
    override def writes(o: TokenKind): JsValue = JsString(o.value) 
    } 

    implicit def tokenKindReads = new Reads[TokenKind] { 
    override def reads(json: JsValue): JsResult[TokenKind] = json match { 
     case JsString(string) => JsSuccess(TokenKind(string)) 
     case _ => JsError("validate.error.invalidTokenKind") 
    } 
    } 

} 
0

私はこの方法で解決し、同様の問題だった:

object VoteType extends Enumeration { 
    val Up, Down = Value 

    implicit val voteTypeMappeer = MappedColumnType.base[VoteType.Value, String](_.toString, VoteType.withName) 
} 
関連する問題