0

抽象的な問題: クラスのコンパニオン オブジェクトに混合できる特性を作成して、そのオブジェクトにそのクラスのオブジェクトを返すメソッドを提供します。

具体的な問題: 次のように、自分自身をシリアル化および逆シリアル化する方法を知っている、RESTful サービス呼び出しで使用するための一連のクラスを作成しようとしています。

case class Foo
(
    var bar : String,
    var blip : String
)
extends SerializeToJson
object Foo extends DeserializeFromJson

使用目的は次のようになります。

var f = Foo( "abc","123" )
var json = f.json
var newF = Foo.fromJson( json )

Gensonグローバルオブジェクトを介してアクセスするシリアライゼーション/デシリアライゼーションを行うために使用しています。

object JSON {
  val parser = new ScalaGenson( new GensonBuilder() <...> )
}

次に、特性を次のように定義します。

trait SerializeToJson {
  def json : String = JSON.parser.toJson(this)
}
trait DeserializeFromJson[T <: DeserializeFromJson[T]] {
  def fromJson( json : String ) : T = JSON.parser.fromJson( json )
}

これはコンパイルされます。しかし、これはしません:

object Foo extends DeserializeFromJson[Foo]

次のエラー メッセージが表示されます。

type arguments [Foo] do not conform to trait DeserializeFromJson's 
type parameter bounds [T <: DeserializeFromJson[T]] 

次のように、単一の特性を作成しようとしました。

trait JsonSerialization[T <: JsonSerialization[T]] {

  def json(implicit m: Manifest[JsonSerialization[T]]) : String = 
    JSON.parser.toJson(this)(m)

  def fromJson( json : String ) : T = 
    JSON.parser.fromJson(json)

}

宣言しただけでは、コンパニオン オブジェクトではなく、 クラスのインスタンスだけがそのメソッドを持っているため、case class Foo (...) extends JsonSerialization[Foo]呼び出すことができません。Foo.fromJsonFoo

宣言object Foo extend JsonSerialization[Foo]すると、コンパイルできFoo.fromJsonメソッドが作成されます。しかし、実行時に、 への呼び出しは、それがではなく であるとfromJson考えます。または、次の実行時エラーが示唆しています。TJsonSerializationFoo

java.lang.ClassCastException: scala.collection.immutable.HashMap$HashTrieMap cannot be cast to ...JsonSerialization
at ...JsonSerialization$class.fromJson(DataModel.scala:14)
at ...Foo.fromJson(Foo.scala:6)

そして、私は得るので宣言することはできませobject Foo extends Foo

module extending its companion class cannot use default constructor arguments

したがって、コンストラクターパラメーターを追加してみると、コンパイルして実行できますが、逆シリアル化しようとしたときのランタイムタイプが間違っているため、上記のエラーが発生します。

私ができる唯一のことはfromJson、すべてのコンパニオン オブジェクトで定義することです。しかし、それを特性で定義する方法がなければならず、その特性を混ぜるだけです。右?

4

3 に答える 3

0

解決策は、特性の型パラメーターを単純化することです。

trait DeserializeFromJson[T] { 
  def fromJson( json : String )(implicit m : Manifest[T]) : T = 
    JSON.parser.fromJson[T](json)(m)
}

これで、コンパニオン オブジェクトを拡張できるようにDeserializeFromJson[Foo]なり、それを呼び出すFoo.fromJson( json )と、適切な型のオブジェクトが作成されるように Genson に正しい型情報を伝えることができます。

于 2016-03-16T15:05:49.260 に答える
0

この問題は、暗黙の動作に関連しています。Genson は、逆シリアル化する必要がある型を知るために使用するマニフェストを期待しています。このマニフェストは、Genson で暗黙的に定義されています。つまり、「呼び出し元コード」で暗黙的に利用可能なマニフェストから取得しようとします。ただし、元のバージョンでは、DeserializeFromJson に Manifest[T] はありません。

別の方法は、そのように DeserializeFromJson を定義することです (暗黙の Manifest[T] 引数を持つコンストラクターを生成するだけです)。

abstract class DeserializeFromJson[T: Manifest] {
  def fromJson( json : String ) : T = JSON.parser.fromJson[T](json)
}

object Foo extends DeserializeFromJson[Foo]

より一般的には、lib (この場合は Genson) をカプセル化することでより多くの価値をもたらさないのであれば、そうすべきではないと思います。基本的にGensonの機能を減らし(現在、人々は文字列でしか作業できません)、ヒットしたような問題を導入します。

于 2016-03-18T18:00:20.453 に答える