import java.net.JarURLConnection
import java.net.URL
import java.net.URLClassLoader
import scala.reflect.runtime.universe
object JarReflection {
def main(args: Array[String]) {
val path = args.head
val url = new URL(s"jar:file:$path!/")
// This would fail if the URL wasn't right. Otherwise we don't need it.
val jarConnection = url.openConnection.asInstanceOf[JarURLConnection]
val manifest = jarConnection.getManifest()
println(s"Creating classloader based on $path")
val urlcl = URLClassLoader.newInstance(Array(url))
val mirror = universe.runtimeMirror(urlcl)
println(mirror.RootClass.toType.members)
}
}
Hi,I'm trying to create a runtime mirror based on a jar file.It should be simply a matter of passing a URLClassLoader to scala.reflect.runtime.universe.runtimeMirror butit doesn't appear to do the trick.I've attached a small program that tries to do it. Run it using `scala JarReflection.scala path_to.jar` e.g.`scala JarReflection.scala /usr/local/Cellar/scala/2.10.2/libexec/lib/scala-library.jar`.In my case it simply outputsCreating classloader based on /usr/local/Cellar/scala/2.10.2/libexec/lib/scala-library.jarScope{final package _root_;final package <empty>}I would've expected the scala package to be there.
Okay, so compiler.RootClass.tpe.declarations makes it possible to traverse all of thethe symbols that are on the class path. Great :)I can't seem to find a method that does this just for the jars that were passed as theclasspath to the compiler though.If I run println(compiler.RootClass.tpe.declarations) it printsScope{
final package scala;
final package doc;
final package sun;
final package com;
final package java;
final package javax;
final package org;
final package apple;
final package sunw;
final package oracle;
final package quicktime;
final package <empty>;
final package _root_
}
I ended up taking a slightly different route:- Get all the classfiles from the jar using http://docs.oracle.com/javase/6/docs/api/java/util/jar/JarFile.html#entries()- Demangle the names- use a runtime mirror based on the class loader of the jar to load all of the entitiesThis approach seems to work.Cheers,Mads
Hi,
Sorry for reviving an old thread.
I've been going through much the same pain (for a different use case: dynamically load all modules implementing a trait). I've passed a bunch of class (and potentially JAR) files to a URLClassLoader (well, the nicer scala.tools.nsc.util.ScalaClassLoader), read the class names from files on disk, looked up the class names in the runtime mirror to find those with a type signature that have the required trait and retrieved the relevant module mirror. All is working to that point.
The critical next step is to get a reference to the module object instance itself with moduleMirror.instance.asInstanceOf[Sims3ResourceHandler]. This is failing with
java.lang.ClassNotFoundException: info.drealm.s3pi.defaultWrapper.DefaultSims3ResourceHandler$
at java.net.URLClassLoader$1.run(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
where "info.drealm.s3pi.defaultWrapper.DefaultSims3ResourceHandler$" is the correct name.
Mads, you said you had an approach that seems to be working for you. Could you expand on this?
You can see my approach here:
https://github.com/pljones/Reflection/blob/master/src/scala/info/drealm/s3pi/WrapperDealer.scala
(I'd also appreciate any improvements to the scala code in general -- I've only been learning it a few weeks.)
Thanks,
-- Peter