我有一个“动态实例化case class”的梦想 - 并根据每个字段的类型提供一些虚拟数据(我将稍后创建一些规则)。到目前为止,我编写了一些可以使用
我觉得在Scala: How to invoke method with type parameter and manifest without knowing the type at compile time?的最后一个回答是一个答案的起点。因此,fill应该采用ClassTag或TypeTag,而不是使用T <:Object?
这段代码起源于How can I transform a Map to a case class in Scala?,其中提到(就像Lift-Framework一样)我确实有liftweb源代码;但是到目前为止,我还没有成功地解开它的所有秘密。
编辑 --- 基于Imm的观点,我已经使下面的代码工作了(对他的答案进行了一些小更新)。
感谢您,Brent。
String
、Long
或Int
的case class的代码...但如果它能够处理嵌套的case class会更好。因此,我可以实例化case class RequiredAPIResponse (stringValue: String, longValue: Long, intValue: Int)
,但无法实例化外部类;其中外部类是...case class Inner (deep: String)
case class Outer (in : Inner)
代码是
def fill[T <: Object]()(implicit mf: ClassTag[T]) : T = {
val declaredConstructors = mf.runtimeClass.getDeclaredConstructors
if (declaredConstructors.length != 1)
Logger.error(/*T.toString + */" has " + declaredConstructors.length + " constructors --- only 1 currently supported.")
val constructor = declaredConstructors.headOption.get
val m = constructor.getParameterTypes.map(p => {
Logger.info("getName " + p.getName +" --- getCanonicalName " + p.getCanonicalName)
Logger.info(p.getCanonicalName)
p.getCanonicalName match {
case "java.lang.String" => /*"Name"->*/ val s : java.lang.String = "DEFAULT STRING"
s
case "long" => /*"Name"-> */ val l : java.lang.Long = new java.lang.Long(99)
l
case "int" => /*"Name"->*/ val i : java.lang.Integer = new java.lang.Integer(99)
i
case _ => /*"Name"->*/
So around here I am stuck!
//THIS IS MADE UP :) But I want to get the "Type" and recursively call fill
//fill[p # Type] <- not real scala code
//I can get it to work in a hard coded manner
//fill[Inner]
}
})
我觉得在Scala: How to invoke method with type parameter and manifest without knowing the type at compile time?的最后一个回答是一个答案的起点。因此,fill应该采用ClassTag或TypeTag,而不是使用T <:Object?
这段代码起源于How can I transform a Map to a case class in Scala?,其中提到(就像Lift-Framework一样)我确实有liftweb源代码;但是到目前为止,我还没有成功地解开它的所有秘密。
编辑 --- 基于Imm的观点,我已经使下面的代码工作了(对他的答案进行了一些小更新)。
def fillInner(cls: Class[_]) : Object = {
val declaredConstructors = cls.getDeclaredConstructors
if (declaredConstructors.length != 1)
Logger.error(/*T.toString + */ " has " + declaredConstructors.length + " constructors --- only 1 currently supported.")
val constructor = declaredConstructors.headOption.get
val m = constructor.getParameterTypes.map(p => {
Logger.info("getName " + p.getName + " --- getCanonicalName " + p.getCanonicalName)
Logger.info(p.getCanonicalName)
p.getCanonicalName match {
case "java.lang.String" => /*"Name"->*/ val s: java.lang.String = "DEFAULT STRING"
s
case "long" => /*"Name"-> */ val l: java.lang.Long = new java.lang.Long(99)
l
case "int" => /*"Name"->*/ val i: java.lang.Integer = new java.lang.Integer(99)
i
case _ => fillInner(p)
}
})
constructor.newInstance(m: _*).asInstanceOf[Object]
}
def fill[T](implicit mf: ClassTag[T]) : T = fillInner(mf.runtimeClass).asInstanceOf[T]
感谢您,Brent。