Прежде всего, есть несколько безопасных альтернатив, которые вы могли бы сделать, если вы просто хотите сократить свой код.Сопутствующий объект можно рассматривать как функцию, поэтому вы можете использовать что-то вроде этого:
def build2[A,B,C](m: Map[A,B], f: (B,B) => C)(k1: A, k2: A): Option[C] = for {
v1 <- m.get(k1)
v2 <- m.get(k2)
} yield f(v1, v2)
build2(m, Image)("url", "title")
Это вернет опцию, содержащую результат.В качестве альтернативы вы можете использовать ApplicativeBuilder
s в Scalaz, которые внутренне делают почти то же самое, но с более приятным синтаксисом:
import scalaz._, Scalaz._
(m.get("url") |@| m.get("title"))(Image)
Если вам действительно нужно сделать это с помощью отражения, то самый простой способ - использовать Paranamer.(как это делает Lift-Framework).Paranamer может восстановить имена параметров, проверив байт-код на предмет снижения производительности и не будет работать во всех средах из-за проблем загрузчика классов (например, REPL).Если вы ограничитесь классами только с параметрами конструктора String
, вы можете сделать это следующим образом:
val pn = new CachingParanamer(new BytecodeReadingParanamer)
def fill[T](m: Map[String,String])(implicit mf: ClassManifest[T]) = for {
ctor <- mf.erasure.getDeclaredConstructors.filter(m => m.getParameterTypes.forall(classOf[String]==)).headOption
parameters = pn.lookupParameterNames(ctor)
} yield ctor.newInstance(parameters.map(m): _*).asInstanceOf[T]
val img = fill[Image](m)
(Обратите внимание, что в этом примере можно выбрать конструктор по умолчанию, поскольку он не проверяет счетчик параметров, которыйвы бы хотели сделать)