[英]Passing type in Scala as an argument
我想将类型传递给Scala中的函数。
问题详细
第一次迭代
我有以下Java类(来自外部源):
public class MyComplexType {
public String name;
public int number;
}
和
public class MyGeneric<T> {
public String myName;
public T myValue;
}
在这个例子中,我想MyComplexType
是实际类型的MyGeneric
; 在真正的问题中有几种可能性。
我想使用Scala代码反序列化JSON字符串,如下所示:
import org.codehaus.jackson.map.ObjectMapper
object GenericExample {
def main(args: Array[String]) {
val jsonString = "{\"myName\":\"myNumber\",\"myValue\":{\"name\":\"fifteen\",\"number\":\"15\"}}"
val objectMapper = new ObjectMapper()
val myGeneric: MyGeneric[MyComplexType] = objectMapper.readValue(jsonString, classOf[MyGeneric[MyComplexType]])
val myComplexType: MyComplexType = myGeneric.myValue
}
}
它编译好,但发生运行时错误:
java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to MyComplexType
at GenericExample$.main(GenericExample.scala:9)
第二次迭代
解决问题的工作方案:
val jsonString = "{\"myName\":\"myNumber\",\"myValue\":{\"name\":\"fifteen\",\"number\":\"15\"}}"
val objectMapper = new ObjectMapper()
val myGeneric: MyGeneric[MyComplexType] = objectMapper.readValue(jsonString, classOf[MyGeneric[MyComplexType]])
myGeneric.myValue = objectMapper.readValue(objectMapper.readTree(jsonString).get("myValue").toString, classOf[MyComplexType])
val myComplexType: MyComplexType = myGeneric.myValue
不好但是很有效。 (如果有人知道如何让它变得更好,那也会受到欢迎。)
第三次迭代
第二次迭代解决方案中的行多次出现在实际问题中,因此我想创建一个函数。 更改变量是JSON格式的字符串和MyComplexType
。
我想要这样的东西:
def main(args: Array[String]) {
val jsonString = "{\"myName\":\"myNumber\",\"myValue\":{\"name\":\"fifteen\",\"number\":\"15\"}}"
val myGeneric = extractMyGeneric[MyComplexType](jsonString)
val myComplexType: MyComplexType = myGeneric.myValue
}
private def extractMyGeneric[T](jsonString: String) = {
val objectMapper = new ObjectMapper()
val myGeneric = objectMapper.readValue(jsonString, classOf[MyGeneric[T]])
myGeneric.myValue = objectMapper.readValue(objectMapper.readTree(jsonString).get("myValue").toString, classOf[T])
myGeneric
}
这不起作用(编译器错误)。 我已经玩过Class
, ClassTag
, classOf
各种组合,但它们都没有帮助。 还有编译器和运行时错误。 你知道如何传递以及如何在Scala中使用这种类型吗? 谢谢!
当您使用jackson
解析json时,您可以使用TypeReference来解析generic
类型。 例:
val jsonString = "{\"myName\":\"myNumber\",\"myValue\":{\"name\":\"fifteen\",\"number\":\"15\"}}"
val objectMapper = new ObjectMapper()
val reference = new TypeReference[MyGeneric[MyComplexType]]() {}
val value: MyGeneric[MyComplexType] = objectMapper.readValue(jsonString, reference)
如果您仍想使用Jackson
,我认为您可以使用TypeReference
类型创建参数。 喜欢:
implicit val typeReference = new TypeReference[MyGeneric[MyComplexType]] {}
val value = foo(jsonString)
println(value.myValue.name)
def foo[T](jsonStr: String)(implicit typeReference: TypeReference[MyGeneric[T]]): MyGeneric[T] = {
val objectMapper = new ObjectMapper()
objectMapper.readValue(jsonStr, typeReference)
}
使用您的方法,我认为您可以使用ClassTag
获取所需的类:
def extractMyGeneric[A : ClassTag](jsonString: String)(implicit generic: ClassTag[MyGeneric[A]]): MyGeneric[A] = {
val classOfA = implicitly[ClassTag[A]].runtimeClass.asInstanceOf[Class[A]]
val classOfMyGenericOfA = generic.runtimeClass.asInstanceOf[Class[MyGeneric[A]]]
val objectMapper = new ObjectMapper()
val myGeneric = objectMapper.readValue(jsonString, classOfMyGenericOfA)
myGeneric.myValue = objectMapper.readValue(objectMapper.readTree(jsonString).get("myValue").toString, classOfA)
myGeneric
}
我对jackson不熟悉,但在play-json中你可以轻松地为你的泛型类定义Reads
import play.api.libs.functional.syntax._
import play.api.libs.json._
implicit def genReads[A: Reads]: Reads[MyGeneric[A]] = (
(__ \ "myName").read[String] and
(__ \ "myValue").read[A]
)((name, value) => {
val e = new MyGeneric[A]
e.myName = name
e.myValue = value
e
})
有了这个,并且只要存在MyComplexType
的Reads
实例,就可以实现你的方法
def extractMyGeneric[A: Reads](jsonString: String): MyGeneric[A] = {
Json.parse(jsonString).as[MyGeneric[A]]
}
这里的问题是你需要为所有复杂类型提供Reads
,这很简单
implicit complexReads: Reads[MyComplexType] = Json.reads[MyComplexType]
如果那些是案例类,那么我认为你必须用genReads
方式手动定义它们与genReads
所做的genReads
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.