mercredi 12 août 2015

Get type parameters from generic type argument and use in recursive function call

def deserialize[X: TypeTag](s: JSONObject): X = {
    val m = ru.runtimeMirror(getClass.getClassLoader)
    val classType = ru.typeOf[X].typeSymbol.asClass
    val cm = m.reflectClass(classType)
    val constructor = typeTag.tpe.decl(ru.termNames.CONSTRUCTOR).asMethod
    val constructorMethod = cm.reflectConstructor(constructor)

    val params = constructor.asMethod.paramLists.head
    val args = new Array[Any](params.length)

    for(i <- params.indices) {
        val name = params(i).name.decodedName.toString
        println(params(i).typeSignature.toString)
        args(i) = params(i).typeSignature match {
            case t if t =:= typeOf[String] => s.getString(name)
            case t if t =:= typeOf[Int] => s.getInt(name)
            case t if t =:= typeOf[Double] => s.getDouble(name)
            case t if t =:= typeOf[Boolean] => s.getBoolean(name)
            case t if t =:= typeOf[Long] => s.getLong(name)
            case t if t =:= typeOf[Array[_]] => deserialize[WeakTypeTag[_]](s.getJSONArray(name))
            case t => deserialize[t.type](s.getJSONObject(name))
        }
    }

    constructorMethod(args:_*).asInstanceOf[X]
}

def deserialize[X: ClassTag: TypeTag](s: JSONArray): Array[X] = {
    val arr = new Array[X](s.length())
    for(i <- 0 until s.length) {
        arr(i) = (typeOf[X] match {
            case x if x =:= typeOf[String] => s.getString(i)
            case x if x =:= typeOf[Int] => s.getInt(i)
            case x if x =:= typeOf[Double] => s.getInt(i)
            case x if x =:= typeOf[Boolean] => s.getInt(i)
            case x if x =:= typeOf[Long] => s.getInt(i)
            case x if x <:< typeOf[Array[_]] => deserialize[TypeTag[_]](s.getJSONArray(i))
            case x => deserialize[X](s.getJSONObject(i))
        }).asInstanceOf[X]
    }
    arr
}

This code is supposed to deserialize a JSON array or JSON object into its respective scala class. The problem I am having is with this line 'case x if x <:< typeOf[Array[]] => deserializeTypeTag[]'. I want the function to detect if the X type argument is an Array of something, and pass that something as the type argument to the recursive function call. So if I call 'deserializeArray[Int]', it should return an 'Array[Array[Int]]'. I need to somehow extract 'Int' from 'Array[Int]' and pass that to 'deserialize???'.





Aucun commentaire:

Enregistrer un commentaire