summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/scala/tools/nsc/util')
-rw-r--r--src/compiler/scala/tools/nsc/util/ClassPath.scala13
-rw-r--r--src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala133
2 files changed, 97 insertions, 49 deletions
diff --git a/src/compiler/scala/tools/nsc/util/ClassPath.scala b/src/compiler/scala/tools/nsc/util/ClassPath.scala
index 1487b42843..1820bd190f 100644
--- a/src/compiler/scala/tools/nsc/util/ClassPath.scala
+++ b/src/compiler/scala/tools/nsc/util/ClassPath.scala
@@ -464,5 +464,16 @@ extends ClassPath[T] {
class JavaClassPath(
containers: IndexedSeq[ClassPath[AbstractFile]],
context: JavaContext)
-extends MergedClassPath[AbstractFile](containers, context) {
+extends MergedClassPath[AbstractFile](containers, context) { }
+
+object JavaClassPath {
+ def fromURLs(urls: Seq[URL], context: JavaContext): JavaClassPath = {
+ val containers = {
+ for (url <- urls ; f = AbstractFile getURL url ; if f != null) yield
+ new DirectoryClassPath(f, context)
+ }
+ new JavaClassPath(containers.toIndexedSeq, context)
+ }
+ def fromURLs(urls: Seq[URL]): JavaClassPath =
+ fromURLs(urls, ClassPath.DefaultJavaContext)
}
diff --git a/src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala b/src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala
index 07fe254410..d048b75599 100644
--- a/src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala
+++ b/src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala
@@ -6,26 +6,34 @@
package scala.tools.nsc
package util
-import java.lang.{ ClassLoader => JavaClassLoader }
+import java.lang.{ ClassLoader => JClassLoader }
import java.lang.reflect.{ Constructor, Modifier, Method }
+import java.io.{ File => JFile }
+import java.net.{ URLClassLoader => JURLClassLoader }
import java.net.URL
+import scala.reflect.unwrapForHandler
import ScalaClassLoader._
import scala.util.control.Exception.{ catching }
+// import Exceptional.unwrap
-trait ScalaClassLoader extends JavaClassLoader {
+trait HasClassPath {
+ def classPathURLs: Seq[URL]
+}
+
+/** A wrapper around java.lang.ClassLoader to lower the annoyance
+ * of java reflection.
+ */
+trait ScalaClassLoader extends JClassLoader {
/** Override to see classloader activity traced */
protected def trace: Boolean = false
/** Executing an action with this classloader as context classloader */
def asContext[T](action: => T): T = {
- val oldLoader = getContextLoader
- try {
- setContextLoader(this)
- action
- }
- finally setContextLoader(oldLoader)
+ val saved = contextLoader
+ try { setContext(this) ; action }
+ finally setContext(saved)
}
- def setAsContext() { setContextLoader(this) }
+ def setAsContext() { setContext(this) }
/** Load and link a class with this classloader */
def tryToLoadClass[T <: AnyRef](path: String): Option[Class[T]] = tryClass(path, false)
@@ -70,68 +78,97 @@ trait ScalaClassLoader extends JavaClassLoader {
val clsToRun = tryToInitializeClass(objectName) getOrElse (
throw new ClassNotFoundException(objectName)
)
-
val method = clsToRun.getMethod("main", classOf[Array[String]])
if (!Modifier.isStatic(method.getModifiers))
throw new NoSuchMethodException(objectName + ".main is not static")
- asContext(method.invoke(null, Array(arguments.toArray: AnyRef): _*)) // !!! : AnyRef shouldn't be necessary
+ try asContext(method.invoke(null, Array(arguments.toArray: AnyRef): _*)) // !!! : AnyRef shouldn't be necessary
+ catch unwrapForHandler({ case ex => throw ex })
}
+
+ /** A list comprised of this classloader followed by all its
+ * (non-null) parent classloaders, if any.
+ */
+ def loaderChain: List[ScalaClassLoader] = this :: (getParent match {
+ case null => Nil
+ case p => p.loaderChain
+ })
}
+/** Methods for obtaining various classloaders.
+ * appLoader: the application classloader. (Also called the java system classloader.)
+ * extLoader: the extension classloader.
+ * bootLoader: the boot classloader.
+ * contextLoader: the context classloader.
+ */
object ScalaClassLoader {
- implicit def apply(cl: JavaClassLoader): ScalaClassLoader = {
- val loader = if (cl == null) JavaClassLoader.getSystemClassLoader() else cl
- new JavaClassLoader(loader) with ScalaClassLoader
+ /** Returns loaders which are already ScalaClassLoaders unaltered,
+ * and translates java.net.URLClassLoaders into scala URLClassLoaders.
+ * Otherwise creates a new wrapper.
+ */
+ implicit def apply(cl: JClassLoader): ScalaClassLoader = cl match {
+ case cl: ScalaClassLoader => cl
+ case cl: JURLClassLoader => new URLClassLoader(cl.getURLs.toSeq, cl.getParent)
+ case _ => new JClassLoader(cl) with ScalaClassLoader
+ }
+ def contextLoader = apply(Thread.currentThread.getContextClassLoader)
+ def appLoader = apply(JClassLoader.getSystemClassLoader)
+ def extLoader = apply(appLoader.getParent)
+ def bootLoader = apply(null)
+ def contextChain = loaderChain(contextLoader)
+
+ def pathToErasure[T: ClassManifest] = pathToClass(classManifest[T].erasure)
+ def pathToClass(clazz: Class[_]) = clazz.getName.replace('.', JFile.separatorChar) + ".class"
+ def locate[T: ClassManifest] = contextLoader getResource pathToErasure[T]
+
+ /** Tries to guess the classpath by type matching the context classloader
+ * and its parents, looking for any classloaders which will reveal their
+ * classpath elements as urls. It it can't find any, creates a classpath
+ * from the supplied string.
+ */
+ def guessClassPathString(default: String = ""): String = {
+ val classpathURLs = contextChain flatMap {
+ case x: HasClassPath => x.classPathURLs
+ case x: JURLClassLoader => x.getURLs.toSeq
+ case _ => Nil
+ }
+ if (classpathURLs.isEmpty) default
+ else JavaClassPath.fromURLs(classpathURLs).asClasspathString
}
- class URLClassLoader(urls: Seq[URL], parent: JavaClassLoader)
- extends java.net.URLClassLoader(urls.toArray, parent)
- with ScalaClassLoader {
+ def loaderChain(head: JClassLoader) = {
+ def loop(cl: JClassLoader): List[JClassLoader] =
+ if (cl == null) Nil else cl :: loop(cl.getParent)
- private var classloaderURLs = urls.toList
+ loop(head)
+ }
+ def setContext(cl: JClassLoader) =
+ Thread.currentThread.setContextClassLoader(cl)
+
+ class URLClassLoader(urls: Seq[URL], parent: JClassLoader)
+ extends JURLClassLoader(urls.toArray, parent)
+ with ScalaClassLoader
+ with HasClassPath {
+
+ private var classloaderURLs: Seq[URL] = urls
private def classpathString = ClassPath.fromURLs(urls: _*)
+ def classPathURLs: Seq[URL] = classloaderURLs
+ def classPath: ClassPath[_] = JavaClassPath fromURLs classPathURLs
/** Override to widen to public */
override def addURL(url: URL) = {
- classloaderURLs +:= url
+ classloaderURLs :+= url
super.addURL(url)
}
- override def run(objectName: String, arguments: Seq[String]) {
- try super.run(objectName, arguments)
- catch { case x: ClassNotFoundException =>
- throw new ClassNotFoundException(objectName +
- " (args = %s, classpath = %s)".format(arguments mkString ", ", classpathString))
- }
- }
override def toString = urls.mkString("URLClassLoader(\n ", "\n ", "\n)\n")
}
- def setContextLoader(cl: JavaClassLoader) = Thread.currentThread.setContextClassLoader(cl)
- def getContextLoader() = Thread.currentThread.getContextClassLoader()
- def getSystemLoader(): ScalaClassLoader = ScalaClassLoader(null)
- def defaultParentClassLoader() = findExtClassLoader()
-
- def fromURLs(urls: Seq[URL], parent: ClassLoader = defaultParentClassLoader()): URLClassLoader =
- new URLClassLoader(urls.toList, parent)
+ def fromURLs(urls: Seq[URL], parent: ClassLoader = null): URLClassLoader =
+ new URLClassLoader(urls, parent)
/** True if supplied class exists in supplied path */
def classExists(urls: Seq[URL], name: String): Boolean =
- (fromURLs(urls) tryToLoadClass name).isDefined
-
- // we cannot use the app classloader here or we get what looks to
- // be classloader deadlock, but if we pass null we bypass the extension
- // classloader and our extensions, so we search the hierarchy to find
- // the classloader whose parent is null. Resolves bug #857.
- def findExtClassLoader(): JavaClassLoader = {
- def search(cl: JavaClassLoader): JavaClassLoader = {
- if (cl == null) null
- else if (cl.getParent == null) cl
- else search(cl.getParent)
- }
-
- search(getContextLoader())
- }
+ fromURLs(urls) tryToLoadClass name isDefined
/** Finding what jar a clazz or instance came from */
def origin(x: Any): Option[URL] = originOfClass(x.getClass)