Skip to content

Commit

Permalink
big fat error message for default mirror failures
Browse files Browse the repository at this point in the history
  • Loading branch information
xeno-by committed Apr 15, 2012
1 parent 364dd41 commit 967ceb2
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 6 deletions.
22 changes: 22 additions & 0 deletions src/library/scala/reflect/ReflectionUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,28 @@ object ReflectionUtils {
case ex if pf isDefinedAt unwrapThrowable(ex) => pf(unwrapThrowable(ex))
}

private def systemProperties: Iterator[(String, String)] = {
import scala.collection.JavaConverters._
System.getProperties.asScala.iterator
}

private def searchForBootClasspath = (
systemProperties find (_._1 endsWith ".boot.class.path") map (_._2) getOrElse ""
)

def show(cl: ClassLoader) = {
def inferClasspath(cl: ClassLoader) = cl match {
case cl: java.net.URLClassLoader => "[" + (cl.getURLs mkString ",") + "]"
case _ => "<unknown>"
}
cl match {
case cl if cl != null =>
"%s of type %s with classpath %s".format(cl, cl.getClass, inferClasspath(cl))
case null =>
"primordial classloader with boot classpath [%s]".format(searchForBootClasspath)
}
}

def defaultReflectionClassLoader() = {
// say no to non-determinism of mirror classloaders
// default classloader will be instantiated using current system classloader
Expand Down
67 changes: 61 additions & 6 deletions src/library/scala/reflect/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package scala
package object reflect {

import ReflectionUtils._
import scala.compat.Platform.EOL

// !!! This was a val; we can't throw exceptions that aggressively without breaking
// non-standard environments, e.g. google app engine. I made it a lazy val, but
Expand All @@ -12,15 +13,69 @@ package object reflect {
// todo. default mirror (a static object) might become a source for memory leaks (because it holds a strong reference to a classloader)!
lazy val mirror: api.Mirror = mkMirror(defaultReflectionClassLoader)

private def mirrorDiagnostics(cl: ClassLoader): String = """
|
| This error has happened because `scala.reflect.runtime.package` located in
| scala-compiler.jar cannot be loaded. Classloader you are using is:
| %s.
|
| In Scala 2.10.0 M3, scala-compiler.jar is required to be on the classpath
| for manifests and type tags to function. This will change in the final release,
| but for now you need to adjust your scripts or build system to proceed.
| Here are the instructions for some of the situations that might be relevant.
|
| If you compile your application directly from the command line
| or a hand-rolled script, this is a bug. Please, report it.
|
| If you compile your application with Maven using the maven-scala plugin,
| set its "fork" configuration entry to "false:
|
| <plugin>
| <groupId>org.scala-tools</groupId>
| <artifactId>maven-scala-plugin</artifactId>
| <version>2.15.0</version>
| <executions>
| <execution>
| <goals>
| ...
| </goals>
| <configuration>
| <fork>false</fork>
| ...
| </configuration>
| </execution>
| </executions>
| </plugin>
|
| If you compile your application with SBT,
| <to be implemented: release SBT for 2.10.0 M3>
|
| If you compile your application in Scala IDE,
| <to be implemented: release Scala IDE for 2.10.0 M3>.
|
| If you launch your application directly from the command line
| or a hand-rolled script, add `scala-compiler.jar` to the classpath:
|
| scalac HelloWorld.scala
| scala HelloWorld -cp path/to/scala-compiler.jar
|
| If you launch your application with Maven using the maven-scala plugin,
| set its "fork" configuration entry to "false as shown above.
|
| If you launch your application with SBT, make sure that you use
| <to be implemented: release SBT for 2.10.0 M3>
|
| If you launch your application in Scala IDE, make sure that both scala-library.jar and scala-compiler.jar
| are in bootstrap entries on the classpath of your launch configuration.
""".stripMargin('|').format(show(cl))

def mkMirror(classLoader: ClassLoader): api.Mirror = {
// we use (Java) reflection here so that we can keep reflect.runtime and reflect.internals in a seperate jar
// note that we must instantiate the mirror with current classloader, otherwise we won't be able to cast it to api.Mirror
// that's not a problem, though, because mirror can service classes from arbitrary classloaders
val instance = invokeFactoryOpt(getClass.getClassLoader, "scala.reflect.runtime.package", "mkMirror", classLoader)
val coreClassLoader = getClass.getClassLoader
val instance = invokeFactoryOpt(coreClassLoader, "scala.reflect.runtime.package", "mkMirror", classLoader)
instance match {
case Some(x: api.Mirror) => x
case Some(_) => throw new UnsupportedOperationException("Available scala reflection implementation is incompatible with this interface")
case None => throw new UnsupportedOperationException("Scala reflection not available on this platform")
case Some(_) => throw new UnsupportedOperationException("Available scala reflection implementation is incompatible with this interface." + mirrorDiagnostics(coreClassLoader))
case None => throw new UnsupportedOperationException("Scala reflection not available on this platform." + mirrorDiagnostics(coreClassLoader))
}
}

Expand Down

0 comments on commit 967ceb2

Please sign in to comment.