diff options
Diffstat (limited to 'src/reflect/scala/reflect/internal/util/ScalaClassLoader.scala')
-rw-r--r-- | src/reflect/scala/reflect/internal/util/ScalaClassLoader.scala | 40 |
1 files changed, 36 insertions, 4 deletions
diff --git a/src/reflect/scala/reflect/internal/util/ScalaClassLoader.scala b/src/reflect/scala/reflect/internal/util/ScalaClassLoader.scala index 41011f6c6b..f3db2017be 100644 --- a/src/reflect/scala/reflect/internal/util/ScalaClassLoader.scala +++ b/src/reflect/scala/reflect/internal/util/ScalaClassLoader.scala @@ -6,15 +6,16 @@ package scala package reflect.internal.util +import scala.language.implicitConversions + import java.lang.{ ClassLoader => JClassLoader } -import java.lang.reflect.{ Constructor, Modifier, Method } -import java.io.{ File => JFile } +import java.lang.reflect.Modifier import java.net.{ URLClassLoader => JURLClassLoader } import java.net.URL -import scala.reflect.runtime.ReflectionUtils.unwrapHandler + +import scala.reflect.runtime.ReflectionUtils.{ show, unwrapHandler } import ScalaClassLoader._ import scala.util.control.Exception.{ catching } -import scala.language.implicitConversions import scala.reflect.{ ClassTag, classTag } trait HasClassPath { @@ -46,6 +47,33 @@ trait ScalaClassLoader extends JClassLoader { def create(path: String): AnyRef = tryToInitializeClass[AnyRef](path).map(_.newInstance()).orNull + /** Create an instance with ctor args, or invoke errorFn before throwing. */ + def create[T <: AnyRef : ClassTag](path: String, errorFn: String => Unit)(args: AnyRef*): T = { + def fail(msg: String) = error(msg, new IllegalArgumentException(msg)) + def error(msg: String, e: Throwable) = { errorFn(msg) ; throw e } + try { + val clazz = Class.forName(path, /*initialize =*/ true, /*loader =*/ this) + if (classTag[T].runtimeClass isAssignableFrom clazz) { + val ctor = { + val maybes = clazz.getConstructors filter (c => c.getParameterCount == args.size && + (c.getParameterTypes zip args).forall { case (k, a) => k isAssignableFrom a.getClass }) + if (maybes.size == 1) maybes.head + else fail(s"Constructor must accept arg list (${args map (_.getClass.getName) mkString ", "}): ${path}") + } + (ctor.newInstance(args: _*)).asInstanceOf[T] + } else { + errorFn(s"""Loader for ${classTag[T]}: [${show(classTag[T].runtimeClass.getClassLoader)}] + |Loader for ${clazz.getName}: [${show(clazz.getClassLoader)}]""".stripMargin) + fail(s"Not a ${classTag[T]}: ${path}") + } + } catch { + case e: ClassNotFoundException => + error(s"Class not found: ${path}", e) + case e @ (_: LinkageError | _: ReflectiveOperationException) => + error(s"Unable to create instance: ${path}: ${e.toString}", e) + } + } + /** The actual bytes for a class file, or an empty array if it can't be found. */ def classBytes(className: String): Array[Byte] = classAsStream(className) match { case null => Array() @@ -111,6 +139,10 @@ object ScalaClassLoader { classloaderURLs :+= url super.addURL(url) } + override def close(): Unit = { + super.close() + classloaderURLs = null + } } def fromURLs(urls: Seq[URL], parent: ClassLoader = null): URLClassLoader = |