2012-12-18 3 views
6

JSONからシリアル化して逆シリアル化する必要があるScalaアプリケーションを作成しています。いくつかのJSONオブジェクトには22以上のフィールドがありますので、ケースクラスは使用できません(フォーマットも変更できません)。私が見つけることができたすべてのScala JSONライブラリは、通常のクラスではなく、ケースクラスだけで(簡単に)動作します。*大文字と小文字を区別しないクラスを使用してJSONからスカラでどのように非直列化できますか?

大規模なJSONオブジェクト(22個以上のフィールドを持つ)をScalaの非大文字クラスに逆シリアル化する最も簡単な方法は何ですか?完全に自動である必要はありませんが、理想的にはMap [String、Any]にデシリアライズして手動ですべてを実行するよりも苦痛の少ないものを探しています。

答えて

4

更新:幸いなことに、私が次のようにフィールド・シリアライザを使用してJson4sジャクソンを使用したかった何をすることが可能になりました:

implicit val formats = DefaultFormats + FieldSerializer[MyNonCaseClass]() 

val myNonCaseClassObject = Serialization.read[MyNonCaseClass](jsonString) 

ここで、以下の要求に応じて、より完全な例です:

import org.json4s.jackson.Serialization 
import org.json4s._ 
import scala.util.Try 

object JSONUtil { 

implicit val formats = DefaultFormats + FieldSerializer[MyNonCaseClass]() + FieldSerializer[MyOtherNonCaseClass](ignore("someUnwantedFieldName") orElse ignore("anotherFieldToIgnore")) + ... 

def toJSON(objectToWrite: AnyRef): String = Serialization.write(objectToWrite) 

def fromJSONOption[T](jsonString: String)(implicit mf: Manifest[T]): Option[T] = Try(Serialization.read(jsonString)).toOption 

} 

使用方法:

val jsonString = JSONUtil.toJSON(myObject) 
val myNewObject: Option[MyClass] = JSONUtil.fromJSONOption[MyClass](aJsonString) 

非caごとにFieldSerializerが必要ですあなたがシリアライズしたいクラスです。また、クラスを定義するときに、JSONから欠落している可能性のあるものはすべてOptionとして定義する必要があります。

SBT:

"org.json4s" %% "json4s-jackson" % "3.2.6" 
+0

こんにちはRyan、あなたはすべてをセットアップする方法についてもう少し詳細を教えていただけますか?私はこれが初めてで、少なくとも輸入が本当に役に立つと思っています! (SBT/MavenリポジトリID/URLも歓迎します!) – fortran

+1

私は上記の答えにもっと完全な例を追加しました。 – Ryan

+0

ありがとうライアン! Scalaは強く静的な型付き言語ですが、IDEのオートコンプリートをJavaのように「探検」するのは難しいと思うことがあります。それは私に一種の失礼を感じさせる... – fortran

3

それは私がコーヒーを飲みながら何もしていなかったとしてThe Play JSON library with generics

を使用してケースクラスなしでそれを行うことが可能です。私はあなたのための例をコードするために自由を取った。次のように完全なソリューションは、次のとおりです。すべての

まず、これはあなたのクラスです:

import play.api.libs.json._ 
import play.api.libs.json.Json._ 


    class TestJSON(
     val field1: String, 
     val field2: String, 
     val field3: String, 
     val field4: String, 
     val field5: String, 
     val field6: String, 
     val field7: String, 
     val field8: String, 
     val field9: String, 
     val field10: String, 
     val field11: String, 
     val field12: String, 
     val field13: String, 
     val field14: String, 
     val field15: String, 
     val field16: String, 
     val field17: String, 
     val field18: String, 
     val field19: String, 
     val field20: String, 
     val field21: String, 
     val field22: String, 
     val field23: String) { 

    } 

    object TestJSON { 
     // 
     // JSON BINDING/UNBINDING 
     // 

     implicit def modalityReads: Reads[TestJSON] = new Reads[TestJSON] { 
     def reads(json: JsValue): TestJSON = 
      new TestJSON(
      field1 = (json \ "field1").as[String], 
      field2 = (json \ "field2").as[String], 
      field3 = (json \ "field3").as[String], 
      field4 = (json \ "field4").as[String], 
      field5 = (json \ "field5").as[String], 
      field6 = (json \ "field6").as[String], 
      field7 = (json \ "field7").as[String], 
      field8 = (json \ "field8").as[String], 
      field9 = (json \ "field9").as[String], 
      field10 = (json \ "field10").as[String], 
      field11 = (json \ "field11").as[String], 
      field12 = (json \ "field12").as[String], 
      field13 = (json \ "field13").as[String], 
      field14 = (json \ "field14").as[String], 
      field15 = (json \ "field15").as[String], 
      field16 = (json \ "field16").as[String], 
      field17 = (json \ "field17").as[String], 
      field18 = (json \ "field18").as[String], 
      field19 = (json \ "field19").as[String], 
      field20 = (json \ "field20").as[String], 
      field21 = (json \ "field21").as[String], 
      field22 = (json \ "field22").as[String], 
      field23 = (json \ "field22").as[String]) 
     } 

     implicit def modalityWrites: Writes[TestJSON] = new Writes[TestJSON] { 
     def writes(ts: TestJSON) = JsObject(Seq(
      "field1" -> JsString(ts.field1), 
      "field2" -> JsString(ts.field2), 
      "field3" -> JsString(ts.field3), 
      "field4" -> JsString(ts.field4), 
      "field5" -> JsString(ts.field5), 
      "field6" -> JsString(ts.field6), 
      "field7" -> JsString(ts.field7), 
      "field8" -> JsString(ts.field8), 
      "field9" -> JsString(ts.field9), 
      "field10" -> JsString(ts.field10), 
      "field11" -> JsString(ts.field11), 
      "field12" -> JsString(ts.field12), 
      "field13" -> JsString(ts.field13), 
      "field14" -> JsString(ts.field14), 
      "field15" -> JsString(ts.field15), 
      "field16" -> JsString(ts.field16), 
      "field17" -> JsString(ts.field17), 
      "field18" -> JsString(ts.field18), 
      "field19" -> JsString(ts.field19), 
      "field20" -> JsString(ts.field20), 
      "field21" -> JsString(ts.field21), 
      "field22" -> JsString(ts.field22), 
      "field23" -> JsString(ts.field23))) 
     } 
    } 

あなたのコントローラは次のようになります。

import play.api._ 
import play.api.mvc._ 
import play.api.libs.json.Json._ 
import play.api.Play.current 
import models.TestJSON 

object Application extends Controller { 

    def getJson = Action { 
    implicit request => 
     Ok(
     toJson(
      Seq(
      toJson(
       new TestJSON(
       "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", 
       "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23")), 
       toJson(new TestJSON(
       "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", 
       "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23"))))) 
    } 

} 

あなたのルートファイル(ちょうどルートアクション) :

GET  /getJson        controllers.Application.getJson 

そして今、真実の瞬間...

curl localhost:9000/getJson 
[{"field1":"1","field2":"2","field3":"3","field4":"4","field5":"5","field6":"6", 
"field7":"7","field8":"8","field9":"9","field10":"10","field11":"11","field12":" 
12","field13":"13","field14":"14","field15":"15","field16":"16","field17":"17"," 
field18":"18","field19":"19","field20":"20","field21":"21","field22":"22","field 
23":"23"},{"field1":"1","field2":"2","field3":"3","field4":"4","field5":"5","fie 
ld6":"6","field7":"7","field8":"8","field9":"9","field10":"10","field11":"11","f 
ield12":"12","field13":"13","field14":"14","field15":"15","field16":"16","field1 
7":"17","field18":"18","field19":"19","field20":"20","field21":"21","field22":"2 
2","field23":"23"}] 

これは逆も同様です。私は現在、それを使って巨大な木を組み立てたり分解したりするプロジェクトに取り組んでいます。それはあなたのために働くはずです。お知らせ下さい。

乾杯!

PS:コードを生成するのに約10分かかりましたが、心配はいりません。私はちょうどList.range(1,24)をマップし、コードを印刷するために "foreach"しました。

+1

はあなたの努力をありがとう、しかし、これは私が(つまり、手動で各フィールドを処理すること)を回避しようとしていたものです。より良いオプションの代わりに、私は今、Jerksonを使ってこれをやっています。少なくとも私のサブオブジェクトは22フィールドよりも小さいので、普通のものを逆シリアル化することができます。 – Ryan

+1

'Reads'と' Writes'インスタンスの両方を定義しているのであれば、 'Format'を使うこともできます。 –

+0

@Travis、yeap、私はプロダクションコードで使っています。乾杯! – wleao

1

Lift JSON APIをご覧ください。

鍵は、解析されるすべてがJValueのサブクラスとして返されることです。

{ 
    "a": [1, 2], 
    "b": "hello" 
} 

のようなオブジェクトは、リフトのAPIを使用すると、Mapのようなものにアクセスでき\のようないくつかの有用な方法を提供

JObject(List(
    JField("a", JArray(List(JInt(1), JInt(2)))), 
    JField("b", JString("hello")) 
)) 

として解析されます。 extractOpt[A]メソッドもあります。これは、解析されたJSONをAに変更するために最善を尽くすメソッドです。それを感じるためにそれらと一緒に遊んでください。

+0

また、プレイライブラリを使って "粗い" JSONマッピングを得ることもできます。そのアイデアは、メソッドやその他の細かい点で素敵なモデルクラスを取得することです。 – fortran

関連する問題