Как отразить метод построения на основе сигнатуры метода в Scala - PullRequest
1 голос
/ 14 мая 2019
class Test(a: String, b: Array[String], c: Array[String]){
  def this(b: Array[String], c: Array[String]) {
    this("1", b, c)
  }

  def this() = {
    this(null, null, null)
  }
}

У меня есть класс Test, как и выше, и я хотел бы использовать отражение scala для вызова одного из них

Я пытаюсь использовать следующий код

import scala.reflect.runtime.{universe => ru}
val clsTest = ru.typeOf[Test].typeSymbol.asClass
val cm = m.reflectClass(clsTest)
val ctor =  ru.typeOf[Test].decl(ru.termNames.CONSTRUCTOR).asTerm.alternatives.map(_.asMethod)

но я не знаю, как выбрать метод на основе сигнатуры метода. Есть ли какой-либо подход к выбору метода, основанного на сигнатуре типа, как Java отражает код? Спасибо!

Я прочитал документ Scala о отражении, но это не решает мою проблему. у него есть только один метод конструктора. Scala Reflect Doc

Ответы [ 2 ]

1 голос
/ 14 мая 2019
// the method as List(list(a,b,c))
// and this is PrimaryConstructor
class Test(a: String, b: Array[String], c: Array[String]) {
  // the method as List(list(b,c))
  def this(b: Array[String], c: Array[String]) {
    this("1", b, c)
  }

  // the method as List(list())
  def this() = {
    this(null, null, null)
  }

  // the method as List(list(a),list(b,c)
  def this(a:String )(b:String,c:String ){
    this(null,null,null)
  }
}

val constructor = typeOf[Test].members
  // filter all constructor
  .filter(e => e.isConstructor).map(e => e.asMethod)
  // find which are you want 
  // edit 1
  .find( e =>{
    val methodParamsType =  e.paramLists.head.map(e =>e.typeSignature)
    // what params  type are you 
    val expectParamsType = List(typeOf[Array[String]],typeOf[Array[String]])

    methodParamsType.length == expectParamsType.length && 
      methodParamsType.zip(expectParamsType).forall{case (l,r)=>l =:= r }
  })
  //   or
  //  .find(e=>e.isPrimaryConstructor)
  //  .find(e=>e.paramLists.head.length == 2)
  .get
0 голосов
/ 15 мая 2019

Я нашел подход для фильтрации по типам параметров

  1. methodName: означает, какой метод вы хотите отразить
  2. allScope: true означает, что найти из this и super , false означает, что найти только из this
  3. types: это типы параметров, вы можете использовать Seq (typeOf [T1], typeOf [T2]): _ *
  4. x: это экземпляр, который будет отражен

ключ в том, что мы можем получить типы параметров метода с помощью methodSymbol.paramLists.head.map (_. Info)

  val ru: scala.reflect.runtime.universe.type = scala.reflect.runtime.universe

  def m: ru.Mirror = {
    ru.runtimeMirror(Thread.currentThread().getContextClassLoader)
  }
//reflect method, method can't be curry
  def reflectMethod[T: ru.TypeTag : ClassTag](methodName: String, allScope: Boolean, types: ru.Type*)(x: T): ru.MethodMirror = {
    val instanceMirror = m.reflect(x)
    val methodSymbols = if (allScope) {
      val members = getTypeTag(x).tpe.member(ru.TermName(methodName))
      if (members.equals(ru.NoSymbol)) {
        throw new NoSuchMethodException(noSuchMethodException(methodName, allScope, types: _*)(x))
      }
      members
        .asTerm
        .alternatives
        .map(_.asMethod)
    } else {
      val decls = getTypeTag(x).tpe.decl(ru.TermName(methodName))
      if (decls.equals(ru.NoSymbol)) {
        throw new NoSuchMethodException(noSuchMethodException(methodName, allScope, types: _*)(x))
      }
      decls
        .asTerm
        .alternatives
        .map(_.asMethod)
    }
    methodSymbols.foreach(item => assert(item.paramLists.size < 2, "we don't support curry method yet"))
    val methodSymbol = methodSymbols.find(item =>
      if (item.paramLists.head.isEmpty) {
        types.isEmpty
      } else {
        if (types.isEmpty) {
          item.paramLists.head.isEmpty
        } else {
          // empty forall is true
          item.paramLists.head.zip(types).forall(pair => pair._1.info =:= pair._2)
        }
      }).getOrElse(throw new NoSuchMethodException(noSuchMethodException(methodName, allScope, types: _*)(x)))

    val methodMirror = instanceMirror.reflectMethod(methodSymbol)
    methodMirror
  }

private def noSuchMethodException[T: ru.TypeTag : ClassTag](methodName: String, allScope: Boolean, types: ru.Type*)(x: T): String = {
    s"no such method: $methodName, allScope: $allScope type: $types in ${getRuntimeClass(x)}"
  }


Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...