4

私は Scala を初めて使用します。ここでは、Argonaut に基づいて汎用の json コンバーターを作成しようとしています。google と stackoverflow で検索してみましたが、今のところわかりません。

これが私のコードのスニペットです。

import org.springframework.http.converter.AbstractHttpMessageConverter
import org.springframework.http.{MediaType, HttpInputMessage, HttpOutputMessage}    
import scala.io.Source
import argonaut._,Argonaut._

case class Currency(code: String)
object Currency {
    implicit def CurrencyCodecJson: CodecJson[Currency] = casecodec1(Currency.apply, Currency.unapply)("code")
}

case class Person(firstName: String, lastName: String)
object Person {
    implicit def PersonCodecJson: CodecJson[Person] = casecodec2(Person.apply, Person.unapply)("firstName", "LastName")
}

class ArgonautConverter extends AbstractHttpMessageConverter[Object](new MediaType("application", "json", Charset.forName("UTF-8")), new MediaType("application", "*+json", Charset.forName("UTF-8"))) {
    val c = classOf[Currency]
    val p = classOf[Person]

    def writeInternal(t: Object, outputStream: OutputStream) = {
        val jsonString = t match {
            case c:Currency => c.asJson.ToString()
            case p:Person => p.asJson.ToString()
    }

    def supports(clazz: Class[_]): Boolean = clazz.isAssignableFrom(classOf[CodecJson])// clazz == classOf[Currency] || clazz == classOf[LegalEntity]

    def readInternal(clazz: Class[_ <: Object], inputStream: InputStream): Object = {
        val jsonString = Source.fromInputStream(inputStream).getLines.mkString
        val jsonObject = clazz match {
            case `c` => jsonString.decodeOption[Currency]
            case `p` => jsonString.decodeOption[Person]
        }
        jsonObject match {
            case Some(j) => j
            case None => null
        }
    }
}

私がやろうとしているのは、将来追加する新しいモデル クラス (この場合は Currency や Person など) ごとに一致を追加し続ける必要がないように一般化することです。

4

2 に答える 2

6

Argonaut には、既に一般的なエンコードおよびデコード機能があります。

たとえばParse.decodeOption、文字列を解析して、コーデックがある任意の型にします。

あなたがしようとしているのは、実行時にタイプのコーデックがあるかどうかを判断することですが、コンパイラーにそれを理解させることができます。

型にデコードできるかどうかは、スコープ内にTの暗黙的なインスタンスがあるかどうかによって異なります。DecodeJson[T](これは のスーパータイプでありCodecJson[T]、それらのいくつかを作成したので、それらは適切です。)

残念ながら、コンパイラはこの制約を推測しないため、型シグネチャで言及する必要があります。これを行う 1 つの方法は、コンテキスト バインドを使用することです。これは、T : DecodeJson以下の例にあります。

def read[T : DecodeJson](inputStream: InputStream): Option[T] = {
  val jsonString = Source.fromInputStream(inputStream).getLines.mkString
  Parse.decodeOption(jsonString)
}

Option[T](また、を使用する代わりに実際に戻る必要があることに注意してくださいnull。)

同様にwrite、署名を使用して実装できます。

def write[T : EncodeJSON](t: T, outputStream: OutputStream)

あなたのCodecJson[T]インスタンスは のインスタンスでもありますEncodeJson[T]

于 2014-01-03T11:09:28.137 に答える
2

可能なすべてのクラスを処理するために単一の Bean は必要ありません。たとえば、クラスごとに Bean を作成できます。

class ArgonautConverter[T: CodecJson : ClassTag] extends AbstractHttpMessageConverter[T]    {    
  def supports(clazz) = clazz == classTag[T].runtimeClass
}
于 2014-01-04T13:26:36.203 に答える