2016-04-05 14 views
0

Scalaでは、私は以下の特性とクラスが定義されているプレイJSONの形質シリアライズ(例示の目的のみに使用される名前):スカラ -

trait Entity { 
    def x() : Collection 
} 

case class X(x : Int, y : Int) extends Entity { 
    def x() : Collection = XCollection() 
} 

case class Y(x : Int, y : Int) extends Entity { 
    def x() : Collection = YCollection() 
} 

クラスのインスタンスは、Webサービスからの応答を解析することによって作成されますがREST API。

レスポンスを解析してレスポンスのクラス表現を返す場合、play-jsonライブラリを使用するアプローチは機能しますが、タイプパラメータを取るジェネリック関数を持つのに対し、T :エンティティ、および例えば、T型

のインスタンスを返すには、次の点を考慮してくださいタイプT考える

def parse[T <: Entity](json : String) : Option[T] = Json.parse(json).asOpt[T](Variants.format[T]) 

、私は、JSON文字列を解析し、型Tのインスタンスを生成したいと思いますインスタンスは特性エンティティの派生物です。しかし、私はリフレクションAPIに関してコンパイルエラーを受けています。

Error:(25, 96) exception during macro expansion: 
scala.ScalaReflectionException: type T is not a class 
at scala.reflect.api.Symbols$SymbolApi$class.asClass(Symbols.scala:323) 
at scala.reflect.internal.Symbols$SymbolContextApiImpl.asClass(Symbols.scala:73) 
at julienrf.variants.Variants$Impl$.baseAndVariants(Variants.scala:132) 
at julienrf.variants.Variants$Impl$.formatDiscriminator(Variants.scala:99) 
at julienrf.variants.Variants$Impl$.format(Variants.scala:94) 
def parse[T <: Entity](json : String) : Option[T] =  Json.parse(json).asOpt[T](Variants.format[T]) 
                         ^

したがって、私はいくつかの助けに感謝します!

おかげ

答えて

2

方が良い暗黙のは、工場のいくつかの種類を使用するよりも、あなたの形式要件を解決することができ:

def parse[T <: Entity](json: String)(implicit r: Reads[T]): Option[T] = 
    Json.parse(json).asOpt[T] 

あなたが暗黙的に定義された現在のコンテキストでのフォーマットを持っている場合はその後、parseが動作します。

implicit val XFormat = Json.format[X] 

parse[X](Json.stringify(Json.toJson(X(1, 2))) // returns X(1, 2) 

更新

あなたが本当にそれを望むなら、それを工場として作ることができます。理論的には暗黙の力学を使いたくないいくつかの異なる状況を想像することができます。あなたはタイプのエンティティのインスタンスを解析する必要があるたび:それでも私は暗黙があなたのために動作しない場合、あなたのコードで

import play.api.libs.json.{Json, Reads} 

    import scala.reflect.runtime.universe._ 

    trait Entity 
    case class X(x : Int, y : Int) extends Entity 
    case class Y(x : Int, y : Int) extends Entity 


    val mapping = Map[Type, Reads[_]](typeOf[X] -> Json.format[X], typeOf[Y] -> Json.format[Y]) 
    def getFormat[T](tpe: Type): Reads[T] = 
    mapping(tpe).asInstanceOf[Reads[T]] 

    def parse[T : TypeTag](json: String): Option[T] = { 
    val map = mapping(implicitly[TypeTag[T]].tpe) 
    Json.parse(json).asOpt[T](getFormat(implicitly[TypeTag[T]].tpe)) 
    } 

    println(parse[X]("""{"x": 5, "y": 6}""")) 
    println(parse[Y]("""{"x": 5, "y": 6}""")) 
+0

をアーキテクチャに問題がある可能性があります問題は有効ですが、左の別のポイントがまだあると思いますつまり、XまたはYインスタンスのいずれかを使用する場合は、書式または読み込みを明示的に指定する必要があります。これは、避けようとしてきたことです。むしろ、私は次のことを求めています:parse [X](jsonString)、parse関数でシリアライザを決定する必要があります。 – dsafa

+0

@dsafaアップデートをご覧ください。 – Archeg

+0

@dsafaフォーマットを明示的に指定する必要はありませんのでご注意ください。最初の例では、形式が暗黙的に指定されているため、キーワードはそこにあります。 – Archeg