diff options
author | Paul Phillips <paulp@improving.org> | 2009-06-12 20:48:56 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2009-06-12 20:48:56 +0000 |
commit | 8d8d1c314706143ef9e21978642df3315fb4a04b (patch) | |
tree | 75d40673b51168dec35537ae2ee783d470d78698 /src | |
parent | b72cc0bda59df3b73afb128b24d86b0cbb1fbf43 (diff) | |
download | scala-8d8d1c314706143ef9e21978642df3315fb4a04b.tar.gz scala-8d8d1c314706143ef9e21978642df3315fb4a04b.tar.bz2 scala-8d8d1c314706143ef9e21978642df3315fb4a04b.zip |
A RichClass for the java side which offers type...
A RichClass for the java side which offers typed Constructors. Working
around bug #1560 and improving on the java interface. Also a small
experiment in the reflection department.
Diffstat (limited to 'src')
-rw-r--r-- | src/dotnet-library/scala/runtime/RichClass.scala | 4 | ||||
-rw-r--r-- | src/library/scala/reflect/RichClass.scala | 91 | ||||
-rw-r--r-- | src/library/scala/util/ClassLoader.scala | 19 |
3 files changed, 94 insertions, 20 deletions
diff --git a/src/dotnet-library/scala/runtime/RichClass.scala b/src/dotnet-library/scala/runtime/RichClass.scala index d8ce949410..a7a781f613 100644 --- a/src/dotnet-library/scala/runtime/RichClass.scala +++ b/src/dotnet-library/scala/runtime/RichClass.scala @@ -13,8 +13,8 @@ package scala.runtime import Predef.Class -final class RichClass(val self: Class[_]) extends Proxy { - +final class RichClass(val self: Class[_]) extends Proxy +{ def isPrimitive(): Boolean = self.IsPrimitive def isArray(): Boolean = self.IsArray diff --git a/src/library/scala/reflect/RichClass.scala b/src/library/scala/reflect/RichClass.scala new file mode 100644 index 0000000000..f016fb37dc --- /dev/null +++ b/src/library/scala/reflect/RichClass.scala @@ -0,0 +1,91 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2002-2009, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +// $Id$ + +package scala.reflect + +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) +} + +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 + } + } +} + diff --git a/src/library/scala/util/ClassLoader.scala b/src/library/scala/util/ClassLoader.scala index 503fdc7202..5663b5b74f 100644 --- a/src/library/scala/util/ClassLoader.scala +++ b/src/library/scala/util/ClassLoader.scala @@ -6,7 +6,7 @@ package scala.util import java.lang.{ ClassLoader => JavaClassLoader } -import java.lang.reflect.{ Modifier, Method } +import java.lang.reflect.{ Constructor, Modifier, Method } import java.net.URL import ScalaClassLoader._ import scala.util.control.Exception.{ catching } @@ -69,23 +69,6 @@ object ScalaClassLoader { def getSystemLoader() = JavaClassLoader.getSystemClassLoader() def defaultParentClassLoader() = findExtClassLoader() - /** XXX move this to RichClass. */ - def callReflectively[T](clazz: Class[_], obj: String, method: String, args: Any*): Option[T] = { - val exceptions = List( - classOf[ClassNotFoundException], - classOf[NoSuchMethodException], - classOf[SecurityException], - classOf[NullPointerException], - classOf[ClassCastException] - ) - - catching(exceptions: _*) opt { - val o: Class[_] = clazz.getClassLoader loadClass obj - val m: Method = o getDeclaredMethod method - m.invoke(o, args map (_.asInstanceOf[AnyRef]) : _*).asInstanceOf[T] - } - } - def fromURLs(urls: Seq[URL]): URLClassLoader = new URLClassLoader(urls.toList, defaultParentClassLoader()) |