我正在生成一组方法,这些方法将从Play JsObject中实例化一个类,例如
class Clazz(val1: Int = 1, val2: String, val3: Option[Int])
def createFromJson(json: JsObject) {
Clazz((json \ "val1").as[Int], (json \ "val2").as[String], (json \ "val3").as[Option[Int]])
}
我们的几个类有超过22个字段,因此使用默认的Writes / Formats来执行此操作是不可行的(无论如何,默认值问题仍然存在)。
我希望能够说出,例如(json \ "val1").asOpt[Int].getOrElse(1)
表示具有默认值的参数。我可以使用所有类的默认值创建一个val defaultValues: Map[String, JsValue]
变量,或者我可以创建一个与输入json合并的val defaultValues: JsObject
,但理想情况下我希望能够提取默认值直接来自类,否则我们将不可避免地更新构造函数的默认值,但不会更新defaultValues
变量的默认值,反之亦然。
有办法做到这一点吗?
答案 0 :(得分:3)
总有办法:)
"拉出班级的默认值"对我来说听起来像运行时反射工作或宏观工作 - 如果你没有任何先前的经验,这也不是一项简单的任务。
这里似乎有一个反思解决方案,你可以适应:How do I access default parameter values via Scala reflection?
但这会影响运行时性能,并可能影响预期的反序列化速度。
我建议使用defaultValues
地图并在处理默认值逻辑的配对对象上创建apply
方法。它将完成工作。
答案 1 :(得分:0)
我建议你在scala 2.11上使用case类:不再有22个字段的限制。 你可以通过宏或反射来做到这一点。 可以使用模块上的apply $ default $来访问成员的默认值。
这是一个示例代码,它提取默认值并返回[String,Any]默认值的映射。
def getDefault[T](c: Context)(T: c.WeakTypeTag[T]): c.Expr[Map[String, Any]] = {
import c.universe._
val classSym = T.tpe.typeSymbol
val moduleSym = classSym.companionSymbol
val apply = moduleSym.typeSignature.declaration(newTermName("apply")).asMethod
// can handle only default parameters from the first parameter list
// because subsequent parameter lists might depend on previous parameters
val kvps = apply.paramss.head.map(_.asTerm).zipWithIndex.flatMap {
case (p, i) =>
if (!p.isParamWithDefault) None
else {
val getterName = newTermName("apply$default$" + (i + 1))
Some(q"${p.name.toString} -> $moduleSym.$getterName")
}
}
c.Expr[Map[String, Any]](q"Map[String, Any](..$kvps)")
}
请注意您的示例代码a" new"不见了。
您好, 阿尔贝托