在scala中,我定义了以下特性和类(名称仅用于说明目的):
trait Entity {
def x() : Collection
}
case class X(x : Int, y : Int) extends Entity {
def x() : Collection = XCollection()
}
case class Y(x : Int, y : Int) extends Entity {
def x() : Collection = YCollection()
}
而类实例是通过解析来自web服务REST API的响应来创建的。
尽管使用play-json库的方法适用于解析响应并返回响应的类表示的情况,但我一直在努力解决以下问题:具有一个接受类型参数的泛型函数,而T:Entity,并返回类型T的实例。
例如,考虑以下内容:
def parse[T <: Entity](json : String) : Option[T] = Json.parse(json).asOpt[T](Variants.format[T])
给定类型T,我希望解析JSON字符串并生成类型T的实例,而该实例是trait Entity的派生。然而,关于反射API:,我一直得到一个编译错误
Error:(25, 96) exception during macro expansion:
scala.ScalaReflectionException: type T is not a class
at scala.reflect.api.Symbols$SymbolApi$class.asClass(Symbols.scala:323)
at scala.reflect.internal.Symbols$SymbolContextApiImpl.asClass(Symbols.scala:73)
at julienrf.variants.Variants$Impl$.baseAndVariants(Variants.scala:132)
at julienrf.variants.Variants$Impl$.formatDiscriminator(Variants.scala:99)
at julienrf.variants.Variants$Impl$.format(Variants.scala:94)
def parse[T <: Entity](json : String) : Option[T] = Json.parse(json).asOpt[T](Variants.format[T])
^
因此,我将感谢您的帮助!
感谢
与使用某种工厂相比,您最好允许implicits解决您的格式要求:
def parse[T <: Entity](json: String)(implicit r: Reads[T]): Option[T] =
Json.parse(json).asOpt[T]
然后,如果您在当前上下文中隐式定义了一种格式,parse
将起作用:
implicit val XFormat = Json.format[X]
parse[X](Json.stringify(Json.toJson(X(1, 2))) // returns X(1, 2)
更新
如果你真的想要的话,你可以把它做成一个工厂。我会质疑这样做是否值得,但理论上我可以想象一些不同的情况,你不想使用隐式力学。尽管如此,我认为如果implicits不适用于您,那么您的代码中可能存在架构问题
import play.api.libs.json.{Json, Reads}
import scala.reflect.runtime.universe._
trait Entity
case class X(x : Int, y : Int) extends Entity
case class Y(x : Int, y : Int) extends Entity
val mapping = Map[Type, Reads[_]](typeOf[X] -> Json.format[X], typeOf[Y] -> Json.format[Y])
def getFormat[T](tpe: Type): Reads[T] =
mapping(tpe).asInstanceOf[Reads[T]]
def parse[T : TypeTag](json: String): Option[T] = {
val map = mapping(implicitly[TypeTag[T]].tpe)
Json.parse(json).asOpt[T](getFormat(implicitly[TypeTag[T]].tpe))
}
println(parse[X]("""{"x": 5, "y": 6}"""))
println(parse[Y]("""{"x": 5, "y": 6}"""))