2

Spray-jsonライブラリは、基本的なScalaタイプをtoJsonメソッドで拡張します。Any基になるタイプにそのようなヒモがあるJsValue場合は、をに変換したいと思います。私の最善の試みはうまくいきますが、冗長です:

import cc.spray._

val maybeJson1: PartialFunction[Any, JsValue] = {
  case x: BigDecimal => x.toJson
  case x: BigInt => x.toJson
  case x: Boolean => x.toJson
  case x: Byte => x.toJson
  case x: Char => x.toJson
  case x: Double => x.toJson
  case x: Float => x.toJson
  case x: Int => x.toJson
  case x: Long => x.toJson
  case x: Short => x.toJson
  case x: String => x.toJson
  case x: Symbol => x.toJson
  case x: Unit => x.toJson
}

理想的には、私はこのようなもの(不可能)を好むでしょう:

def maybeJson2(any: Any): Option[JsValue] = {
  if (pimpExistsFor(any))
    Some(any.toJson)
  else
    None  
}

強化されたすべてのタイプを列挙せずにこれを行う方法はありますか?

4

2 に答える 2

3

方法はありますが、多くの反省が必要であるため、かなりの頭痛の種です。基本的な考え方は次のとおりです。オブジェクトは、メソッドを含む暗黙のDefaultJsonProtocolオブジェクトを含む一連のトレイトを継承しますwrite。それぞれにアクセサ機能がありますが、それが何と呼ばれているのかわかりません。基本的には、パラメーターを受け取らないすべてのwriteメソッドを取得し、オブジェクトのクラスを取得して。を返すメソッドを持つ1つのオブジェクトを返しますJsValue。そのようなクラスを1つ返すそのようなメソッドが1つだけ見つかった場合は、リフレクションを使用してそれを呼び出します。そうでなければ、保釈します。

これは次のようになります警告、テストされていません):

def canWriteMe(writer: java.lang.Class[_], me: java.lang.Class[_]): 
  Option[java.lang.reflect.Method] =
{
  writer.getMethods.find(_.getName == "write").filter{ m =>
    classOf[JsValue].isAssignableFrom(m.getReturnType) && {
      val parm = m.getParameterTypes()
      m.length == 1 && parm(0).isAssignableFrom(me)
    }
  }
}
def maybeJson2(any: Any): Option[JsValue] = {
  val couldWork = {
    DefaultJsonProtocol.getClass.getMethods.
      filter(_.getParameterTypes.length==0).
      flatMap(m => canWriteMe(m.getReturnType, any.getClass).map(_ -> m))
  }
  if (couldWork.length != 1) None else {
    couldWork.headOption.map{ case (wrMeth, obMeth) =>
      val wrObj = obMeth.invoke(DefaultJsonProtocol)
      val answer = wrMeth.invoke(wrObj, any)
    }
  }
}

DefaultJsonProtocolとにかく、 REPLでクラスを段階的に分解し、ライターを定義するオブジェクトを確実に識別して、それらからメソッドを取得する方法を見つけるのが最善ですwrite

于 2012-05-26T23:33:20.013 に答える
0

それがあなたのニーズに合うかどうかはわかりませんが、これは本当にシンプルでタイプセーフな代替アプローチです。

(を使用する代わりにAny)引数の型を保持した場合、コンパイル時に正しい変換を見つけるために暗黙のパラメーター解決に依存することができます。

def toJson[T:JsonFormat]( t: T ): JsValue = implicitly[JsonFormat[T]].write(t)

「pimpable」ではない引数を渡そうとすると、コンパイル時にプログラムが失敗するため、オプションは必要ありません。

于 2012-05-27T11:39:54.150 に答える