2017-12-15 7 views
0

私は、json4s(scala)を介して異なる内部のケースクラスに解析したい、さまざまな外部JSONエンティティをたくさん持っています。 json4sのextract関数を使ってすべてうまく動作します。私は型とjsonの文字列を取り、文字列を型/ケースクラスに解析する解析関数を実装しました。私はここで繰り返しを好きではないこのスカラの文字列からクラス型へのマッピングを作成

entityName match { 
case "entity1" => JsonParser.parse[Entity1](jsonString) 
case "entity2" => JsonParser.parse[Entity2](jsonString) 
.... 

のように見える私は、パターンマッチング機能を実装した正しいケースクラス、正しいJSON文字列をマップするために、このようなマップを経由してこのマッピングをやりたいです:私は一度だけこれが機能していません。この

JsonParser.parse[mapping(entityName)](jsonString) 

ようJsonParser.parse機能を実装することができる場所で、このマップでは

val mapping = Map(
"entity1" -> Entity1, 
"entity2" -> Entity2 
.... 

、マップはREFEREであるため、 Class型ではなくオブジェクトにネーシングします。私もclassOf [Entity1]を試しましたが、これも動作しません。これを行う方法はありますか?

ありがとうございます!

+0

...実行時のものとコンパイル時のものを混在させています。 –

答えて

0

:のような(match/caseを必要とせずに)タイプを使用するのに十分であるまあ

{ 
    import $ivy.`org.json4s::json4s-native:3.6.0-M2` 
    import org.json4s.native.JsonMethods.parse 
    import org.json4s.DefaultFormats 
    import org.json4s.JValue 

    case class Entity1(name : String, value : Int) 
    case class Entity2(name : String, value : Long) 

    implicit val formats = DefaultFormats 
    def extract[T](input : JValue)(implicit m : Manifest[T]) = input.extract[T] 

    val mapping: Map[String, Manifest[_]] = Map(
     "entity1" -> implicitly[Manifest[Entity1]], 
     "entity2" -> implicitly[Manifest[Entity2]] 
    ) 

    val input = parse(""" { "name" : "abu", "value" : 1 } """) 
    extract(input)(mapping("entity1")) //Entity1("abu", 1) 
    extract(input)(mapping("entity2")) //Entity2("abu", 1L) 
    } 
+0

@SergGrの回答と組み合わせて、本当に役に立ちました。 – Lothium

1

あなたのJsonParser.parseを動作させる方法はScalaでは不可能です。 Scalaは強く静的に型付けされた言語です。これは、コンパイラがコンパイル時に値の型を知っていることを確認して、有効なフィールドとメソッドのみにアクセスし、有効なパラメータとしてメソッドに渡すことを検証できることを意味します。あなたのクラスを想定し

case class Entity1(value:Int, unique1:Int) 
case class Entity2(value:String, unique2:String) 

であり、あなたはコンパイラがparsed.valueの種類を知っているかparsed.unique2がない間parsed.unique1が有効なフィールドであることを知ることがparsedの種類を知ることができる方法

val parsed = JsonParser.parse[mapping("entity1")](jsonString) 

を書くのか?最適な型のコンパイラがparsedに割り当てることができるのは、Anyのような非常に一般的なものです。もちろん、Anyを特定のタイプにダウンキャストすることができますが、これはどんな種類の目的を果たしているのかをasInstanceOfで明示的に指定しなければならないことを意味します。

import org.json4s.jackson.JsonMethods 
implicit val formats = org.json4s.DefaultFormats // or whatever Formats you actually need 

val typeMap: Map[String, scala.reflect.Manifest[_]] = Map(
    "String" -> implicitly[scala.reflect.Manifest[String]], 
    "Int" -> implicitly[scala.reflect.Manifest[Int]] 
) 

def parseAny(typeName: String, jsonString: String): Any = { 
    val jValue = JsonMethods.parse(jsonString) 
    jValue.extract(formats, typeMap(typeName)) 
} 

をしてから、このような何か::それでも、何とかAnyを返すことはあなたのためにOKであれば、あなたはこのような何かをしようとするかもしれ

def testParseByTypeName(typeName: String, jsonString: String): Unit = { 
    try { 
    val parsed = parseAny(typeName, jsonString) 
    println(s"parsed by name $typeName => ${parsed.getClass} - '$parsed'") 
    } catch { 
    case e => println(e) 
    } 
} 

def test() = { 
    testParseByTypeName("String", "\"abc\"") 
    testParseByTypeName("Int", "123") 
} 

P.S.をentityNameが外部から来ていない場合(つまり、実際のタイプを見つけるためにデータを分析しない場合)、実際にはそれを必要としません。アンモナイトREPLに貼り付けるためのスニペットとして、@SergGrからアイデア後

def parse[T](jsonString: String)(implicit mf: scala.reflect.Manifest[T]): T = { 
    val jValue = JsonMethods.parse(jsonString) 
    jValue.extract[T] 
} 

def testParse[T](prefix: String, jsonString: String)(implicit mf: scala.reflect.Manifest[T]): Unit = { 
    try { 
    val parsed = parse[T](jsonString) 
    println(s"$prefix => ${parsed.getClass} - '$parsed'") 
    } catch { 
    case e => println(e) 
    } 
} 

def test() = { 
    testParse[String]("parse String", "\"abc\"") 
    testParse[Int]("parse Int", "123") 
} 
関連する問題