2

Spray-json库使用方法扩展了基本的 Scala 类型toJson。如果底层类型存在这样的皮条客,我想将其转换Any为 a 。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方法,该方法采用您的对象的类并返回一个JsValue. 如果您恰好找到一种这样的方法返回一个这样的类,请使用反射来调用它。否则,保释。

它看起来这样(警告,未经测试):

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 回答