/* __ *\ ** ________ ___ / / ___ Scala API ** ** / __/ __// _ | / / / _ | (c) 2002-2009, LAMP/EPFL ** ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** ** /____/\___/_/ |_/____/_/ | | ** ** |/ ** \* */ // $Id$ package scala.reflect import annotation.experimental import util.control.Exception._ import util.ScalaClassLoader._ import java.lang.{ Class => JClass } import java.lang.reflect. { Constructor => JConstructor } object RichClass { // We can't put this in Predef at the moment because everything referenced // from Predef has to be buildable at the first bootstraping phase. implicit def classWrapper[T](x: JClass[T]): RichClass[T] = new RichClass(x) } @experimental final class RichClass[T](val self: JClass[T]) extends Proxy { // The getConstructors and getDeclaredConstructors methods on java.lang.Class[T] // return "raw type" Constructors rather than Constructor[T]s as one would want. // The "why" from http://java.sun.com/javase/6/docs/api/java/lang/Class.html is: // // Note that while this method returns an array of Constructor<T> objects (that is an array // of constructors from this class), the return type of this method is Constructor<?>[] and // not Constructor<T>[] as might be expected. This less informative return type is necessary // since after being returned from this method, the array could be modified to hold Constructor // objects for different classes, which would violate the type guarantees of Constructor<T>[] // // Since this reasoning is invalid in scala due to its abandonment of Array covariance, // these methods exist to correct the return types. // // In addition, at this writing because of ticket #1560 the compiler crashes on the // untyped constructors but not on these. def getConstructorsTyped(): Array[JConstructor[T]] = self.getConstructors() map (_.asInstanceOf[JConstructor[T]]) def getDeclaredConstructorsTyped(): Array[JConstructor[T]] = self.getDeclaredConstructors() map (_.asInstanceOf[JConstructor[T]]) private lazy val classLoader = self.getClassLoader match { case null => getSystemLoader case x => x } private val exceptions = List( classOf[ClassNotFoundException], classOf[NoSuchMethodException], classOf[SecurityException], classOf[NullPointerException], classOf[ClassCastException] ) // Experimental! // scala> classOf[String].reflectiveCall[Array[String]]("ababab", "split")("b") // res0: Array[String] = Array(a, a, a) /** A class representing a reflective method call. It is a function object * and will make the call with whatever args are given via apply, or it will * throw an exception at that point if there was an error in creation. */ class ReflectiveCall[+U](obj: T, name: String) { def methodForArgs(args: AnyRef*) = self.getMethod(name, args map (_.getClass) : _*) def isErroneous = false def apply(args: Any*): U = { val ps = args map (_.asInstanceOf[AnyRef]) val m = methodForArgs(ps: _*) m.invoke(obj, ps: _*).asInstanceOf[U] } } class FailedReflectiveCall[+U](ex: Throwable) extends ReflectiveCall[U](null.asInstanceOf[T], null) { override def isErroneous = true override def apply(args: Any*) = throw ex } def reflectiveCall[U](obj: T, method: String): ReflectiveCall[U] = { (catching(exceptions: _*) either (new ReflectiveCall[U](obj, method))) match { case Left(x) => new FailedReflectiveCall[U](x) case Right(x) => x } } }