2016-09-20 5 views
1

我々はそのような単純なことができて作業するScala 2.11.8Play framework 2.5.8プレイでJSONに列挙して地図を解析することができませんScalaの

データを使用します。

object EnumA extends Enumeration { 
    type EnumA = Value 
    val ONE, TWO, THREE = Value 
} 

case class NoWork(data: Map[EnumA.Value, String] = Map.empty) 

そして、何私がアーカイブすることにありますNoWorkクラスをJsonに解析することができます。 Enumerationの暗黙的なフォーマッタを用意する必要があることはわかっています。

私はこの解決策を見つけました:https://stackoverflow.com/a/15489179/1549135これを適用しました。

object NoWork { 
    implicit val enumAFormat = EnumUtils.enumFormat(EnumA) 

    implicit val jsonModelFormat = Json.format[NoWork] 
} 

をそしてそれは常にエラーで失敗します:

error: No implicit format for Map[EnumA.Value,String] available. 
     implicit val jsonModelFormat = Json.format[NoWork] 
               ^

問題は何である次のように、これらの暗黙の提供

コンパニオンオブジェクトに見えますか?

dataのタイプをMap[String, String]にテストして変更して、シリアル化が可能です。 Enum自体もシリアル化可能ですので、MapEnumタイプで修正するにはどうすればよいですか?

ありがとうございます!

編集

Pamuの答え

implicit val writes = new Writes[Map[EnumA.Value, String]] { 
    override def writes(o: Map[EnumA.Value, String]): JsValue = Json.toJson(o.map { case (a, b) => Json.parse(s"""{${Json.toJson(a)}:${Json.toJson(b)}}""")}.toList) 
} 

は明らかにこの状況のために働くだろうと、私は実際に私は、アプリケーション全体で使用することができ、他のMap[Enum, T]のための一般的な解決策が必要になります。

答えて

0

Stringのタイプは、JsObjectkeyのように常にStringに変換されます。他のパラメータは、汎用的であるとimplicit format: Format[T]

import play.api.data.validation.ValidationError 
import play.api.libs.json._  
import scala.util.{Failure, Success, Try} 

class MapEnumFormat[E <: Enum[E], T](valueOf: (String => E))(implicit format: Format[T]) extends Format[Map[E, T]] { 

    override def writes(o: Map[E, T]): JsValue = { 
    JsObject(o.map { case (a, b) => (a.name, Json.toJson(b)) }) 
    } 

    override def reads(json: JsValue): JsResult[Map[E, T]] = { 
    val result = Try(json.as[Map[String, T]].map { 
     case (key, value) => 
     valueOf(key) -> value 
    }) 

    result match { 
     case Success(status) => 
     JsSuccess(status) 
     case Failure(th) => 
     JsError(ValidationError(s"Error while serializing $json: $th")) 
    } 
    } 

} 
2

Jsonキーが文字列であることが必須であることに注意してください。有効なJSONのためのキーは常に文字列でなければなりませんので、次のコード

は動作しません

Json.toJson(Map("mon" -> EnumA.MON)) 

次のコードを動作します。ここで鍵はStringではないEnumA.Valueです。

scala> Json.toJson(Map(EnumA.MON -> "mon")) 
    <console>:19: error: No Json serializer found for type scala.collection.immutable.Map[EnumA.Value,String]. Try to implement an implicit Writes or Format for this type. 
      Json.toJson(Map(EnumA.MON -> "mon")) 

しかし、あなたが期待通りに動作したい場合は、あなたが

object EnumA extends Enumeration { 
    val MON = Value("monday") 
    val TUE = Value("Tuesday") 

    implicit val format = new Format[EnumA.Value] { 
     override def writes(o: EnumA.Value): JsValue = Json.toJson(o.toString) 
     override def reads(json: JsValue): JsResult[EnumA.Value] = json.validate[String].map(EnumA.withName(_)) 
    } 
    } 
を以下のよう EnumAのためのフォーマットを宣言することができ

Json.toJson(Map(EnumA.MON -> "hello")) 

を作品writes

implicit val writes = new Writes[Map[EnumA.Value, String]] { 
     override def writes(o: Map[EnumA.Value, String]): JsValue = Json.toJson(o.map { case (a, b) => Json.parse(s"""{${Json.toJson(a)}:${Json.toJson(b)}}""")}.toList) 
    } 

今、次のコードを提供します3210

ScalaのREPLの出力我々はMap[E <: Enum[E], T]タイプのためのJSONのシリアル化を提供し、一般的なクラスを用意している同僚と

scala>  object EnumA extends Enumeration { 
    |   val MON = Value("monday") 
    |   val TUE = Value("Tuesday") 
    | 
    |   implicit val format = new Format[EnumA.Value] { 
    |   override def writes(o: EnumA.Value): JsValue = Json.toJson(o.toString) 
    |   override def reads(json: JsValue): JsResult[EnumA.Value] = json.validate[String].map(EnumA.withName(_)) 
    |   } 
    |  } 
defined object EnumA 

scala> Json.toJson(EnumA.MON) 
res0: play.api.libs.json.JsValue = "monday" 

scala> (Json.parse("""{"a": "monday"}""") \ "a").validate[EnumA.Value] 
res7: play.api.libs.json.JsResult[EnumA.Value] = JsSuccess(monday,) 

scala> (Json.parse("""{"a": "monday"}""") \ "a").validate[EnumA.Value].get 
res10: EnumA.Value = monday 

scala> Json.toJson(Map("mon" -> EnumA.MON)) 
res2: play.api.libs.json.JsValue = {"mon":"monday"} 

scala> Json.toJson(Map(EnumA.MON -> "mon")) 
<console>:19: error: No Json serializer found for type scala.collection.immutable.Map[EnumA.Value,String]. Try to implement an implicit Writes or Format for this type. 
     Json.toJson(Map(EnumA.MON -> "mon")) 

scala> implicit val writes = new Writes[Map[EnumA.Value, String]] { 
    |  override def writes(o: Map[EnumA.Value, String]): JsValue = Json.toJson(o.map { case (a, b) => Json.parse(s"""{${Json.toJson(a)}:${Json.toJson(b)}}""")}.toList) 
    |  } 
writes: play.api.libs.json.Writes[Map[EnumA.Value,String]] = [email protected] 

scala> Json.toJson(Map(EnumA.MON -> "hello")) 
res2: play.api.libs.json.JsValue = [{"monday":"hello"}] 
+0

を使用して変換されます。しかし、私が話したように、 'Enum'が正常に動作します。しかし、 'Map [Enum、String]'はそうではありません。 – Atais

+0

@Atais ...答えを編集しました。あなたが期待しているものをチェックしてください。これが役に立ったと思っています – pamu

+0

しかし、私はもともと約 – Atais

関連する問題