Какой-либо способ получить доступ к типу объявления Опции Scala во времени выполнения с помощью отражения?

Так, у меня есть класс Scala, который похож на это:

class TestClass {
  var value: Option[Int] = None
}

и я занимаюсь проблемой, где у меня есть Строковое значение, и я хочу принудить его в ту Опцию [Интервал] во времени выполнения с помощью отражения. Так, в другой части кода (который ничего не знает о TestClass) у меня есть некоторый код как это:

def setField[A <: Object](target: A, fieldName: String, value: String) {
  val field = target.getClass.getDeclaredField(fieldName)
  val coercedValue = ???; // How do I figure out that this needs to be Option[Int] ? 
  field.set(target, coercedValue)   
}

Чтобы сделать это, я должен знать, что полем является Опция и что параметр типа Опции является Интервалом.

Каковы мои опции для выяснения, что тип 'значения' является Опцией [Интервал] во времени выполнения (т.е. использование отражения)?

Я видел подобные проблемы, решенные путем аннотирования поля, например, @OptionType (Int.class). Я предпочел бы решение, которое не потребовало аннотаций на отражательную цель, если это возможно.

13
задан giampaolo 13 February 2014 в 21:20
поделиться

4 ответа

С помощью API отражения Java 1.5 довольно просто:

 def isIntOption(clasz: Class[_], propertyName: String) = {
   var result = 
     for {
       method <- cls.getMethods
       if method.getName==propertyName+"_$eq"
       param <- method.getGenericParameterTypes.toList.asInstanceOf[List[ParameterizedType]]
     } yield
       param.getActualTypeArguments.toList == List(classOf[Integer]) 
       && param.getRawType == classOf[Option[_]]
   if (result.length != 1)
     throw new Exception();
   else
     result(0)
 }
5
ответ дан 2 December 2019 в 01:10
поделиться

Проблема в том, что JVM реализует универсальные шаблоны посредством стирания типов. Таким образом, невозможно обнаружить посредством отражения, что типом значения является Option [Int] , потому что во время выполнения на самом деле это не так: это просто Option !

В 2.8 вы должны иметь возможность использовать манифесты следующим образом:

var value: Option[Int] = None
val valueManifest = implicitly[scala.reflect.Manifest[Option[Int]]]
valueManifest.typeArguments // returns Some(List(Int))
1
ответ дан 2 December 2019 в 01:10
поделиться
class TestClass {
  var value: Option[Int] = None
// ...

  def doSomething {
    value match {
      case Some(i) => // i is an Int here
      case None =>
      // No other possibilities
    }
  }
}
2
ответ дан 2 December 2019 в 01:10
поделиться

На уровне байтового кода Java не имеет универсальных шаблонов. Обобщения реализованы с помощью полиморфизма, поэтому после компиляции исходного кода (в данном случае Scala) универсальные типы исчезают (это называется стиранием типа ). Это делает невозможным сбор информации об общем типе среды выполнения посредством отражения.

Возможный - хотя и немного грязный - обходной путь - получить тип среды выполнения для свойства, которое, как вы знаете, имеет тот же тип, что и параметр Generic. Для экземпляров Option мы можем использовать get member

object Test {

  def main(args : Array[String]) : Unit = {
    var option: Option[_]= None
    println(getType(option).getName)
    option = Some(1)
    println(getType(option).getName)

  }

  def getType[_](option:Option[_]):Class[_]= {
         if (option.isEmpty) classOf[Nothing] else (option.get.asInstanceOf[AnyRef]).getClass
  }
}
3
ответ дан 2 December 2019 в 01:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: