From 8d8d1c314706143ef9e21978642df3315fb4a04b Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Fri, 12 Jun 2009 20:48:56 +0000 Subject: 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. --- src/dotnet-library/scala/runtime/RichClass.scala | 4 +- src/library/scala/reflect/RichClass.scala | 91 ++++++++++++++++++++++++ src/library/scala/util/ClassLoader.scala | 19 +---- 3 files changed, 94 insertions(+), 20 deletions(-) create mode 100644 src/library/scala/reflect/RichClass.scala 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 objects (that is an array + // of constructors from this class), the return type of this method is Constructor[] and + // not Constructor[] 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[] + // + // 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()) -- cgit v1.2.3