Scala库使用toJson方法扩展了基本的spray-json类型。如果底层类型有这样的皮条客,我希望将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
}有没有一种方法可以做到这一点,而不是枚举每一种已经被丰富的类型?
发布于 2012-05-27 07:33:20
有一种方法,但它需要大量的思考,因此是相当令人头疼的。其基本思想如下。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)
}
}
}无论如何,您最好逐步拆分REPL中的DefaultJsonProtocol类,并了解如何可靠地识别定义编写器的对象,然后从中获取write方法。
发布于 2012-05-27 19:39:54
我不确定它是否能满足您的需要,但这里有一个非常简单且类型安全的替代方法。
如果您保留参数的类型(而不是使用Any),则可以依靠隐式参数解析在编译时找到正确的转换:
def toJson[T:JsonFormat]( t: T ): JsValue = implicitly[JsonFormat[T]].write(t)你不需要一个选项,因为如果你试图传递一个不是"pimpable“的参数,程序将在编译时失败。
https://stackoverflow.com/questions/10770344
复制相似问题