11package dotty .tools
22package runner
33
4- import java .lang .invoke .{MethodHandles , MethodType }
5-
64import scala .language .implicitConversions
7- import java .lang .{ClassLoader => JClassLoader }
5+
6+ import java .lang .ClassLoader
7+ import java .lang .invoke .{MethodHandles , MethodType }
88import java .lang .reflect .Modifier
9- import java .net .{URLClassLoader => JURLClassLoader }
10- import java .net . URL
9+ import java .net .{ URL , URLClassLoader }
10+ import java .lang . reflect .{ InvocationTargetException , UndeclaredThrowableException }
1111
12+ import scala .annotation .internal .sharable
1213import scala .annotation .tailrec
1314import scala .util .control .Exception .catching
14- import scala .reflect .{ClassTag , classTag }
15- import java .lang .reflect .InvocationTargetException
16- import java .lang .reflect .UndeclaredThrowableException
17- import dotty .tools .repl .AbstractFileClassLoader
18- import dotty .tools .io .AbstractFile
19- import dotty .tools .io .Streamable
20- import scala .annotation .internal .sharable
2115
22- trait HasClassPath {
23- def classPathURLs : Seq [URL ]
24- }
25-
26- final class RichClassLoader (private val self : JClassLoader ) extends AnyVal {
16+ final class RichClassLoader (private val self : ClassLoader ) extends AnyVal {
2717 /** Executing an action with this classloader as context classloader */
28- def asContext [T ](action : => T ): T = {
18+ private def asContext [T ](action : => T ): T = {
2919 val saved = Thread .currentThread.getContextClassLoader
3020 try { ScalaClassLoader .setContext(self) ; action }
3121 finally ScalaClassLoader .setContext(saved)
3222 }
3323
3424 /** Load and link a class with this classloader */
3525 def tryToLoadClass [T <: AnyRef ](path : String ): Option [Class [T ]] = tryClass(path, initialize = false )
26+
3627 /** Load, link and initialize a class with this classloader */
3728 def tryToInitializeClass [T <: AnyRef ](path : String ): Option [Class [T ]] = tryClass(path, initialize = true )
3829
3930 private def tryClass [T <: AnyRef ](path : String , initialize : Boolean ): Option [Class [T ]] =
4031 catching(classOf [ClassNotFoundException ], classOf [SecurityException ]) opt
4132 Class .forName(path, initialize, self).asInstanceOf [Class [T ]]
4233
43- /** Create an instance of a class with this classloader */
44- def create (path : String ): AnyRef =
45- tryToInitializeClass[AnyRef ](path).map(_.getConstructor().newInstance()).orNull
46-
47- /** Create an instance with ctor args, or invoke errorFn before throwing. */
48- def create [T <: AnyRef : ClassTag ](path : String , errorFn : String => Unit )(args : AnyRef * ): T = {
49- def fail (msg : String ) = error(msg, new IllegalArgumentException (msg))
50- def error (msg : String , e : Throwable ) = { errorFn(msg) ; throw e }
51- try {
52- val clazz = Class .forName(path, /* initialize =*/ true , /* loader =*/ self)
53- if (classTag[T ].runtimeClass isAssignableFrom clazz) {
54- val ctor = {
55- val maybes = clazz.getConstructors filter (c => c.getParameterCount == args.size &&
56- (c.getParameterTypes zip args).forall { case (k, a) => k isAssignableFrom a.getClass })
57- if (maybes.size == 1 ) maybes.head
58- else fail(s " Constructor must accept arg list ( ${args map (_.getClass.getName) mkString " , " }): ${path}" )
59- }
60- (ctor.newInstance(args : _* )).asInstanceOf [T ]
61- } else {
62- errorFn(s """ Loader for ${classTag[T ]}: [ ${show(classTag[T ].runtimeClass.getClassLoader)}]
63- |Loader for ${clazz.getName}: [ ${show(clazz.getClassLoader)}] """ .stripMargin)
64- fail(s " Not a ${classTag[T ]}: ${path}" )
65- }
66- } catch {
67- case e : ClassNotFoundException =>
68- error(s " Class not found: ${path}" , e)
69- case e @ (_ : LinkageError | _ : ReflectiveOperationException ) =>
70- error(s " Unable to create instance: ${path}: ${e.toString}" , e)
71- }
72- }
73-
74- /** The actual bytes for a class file, or an empty array if it can't be found. */
75- def classBytes (className : String ): Array [Byte ] = classAsStream(className) match {
76- case null => Array ()
77- case stream => Streamable .bytes(stream)
78- }
79-
80- /** An InputStream representing the given class name, or null if not found. */
81- def classAsStream (className : String ) = self.getResourceAsStream {
82- if (className endsWith " .class" ) className
83- else s " ${className.replace('.' , '/' )}.class " // classNameToPath
84- }
85-
8634 /** Run the main method of a class to be loaded by this classloader */
8735 def run (objectName : String , arguments : Seq [String ]): Unit = {
88- val clsToRun = tryToInitializeClass(objectName) getOrElse (
89- throw new ClassNotFoundException (objectName)
90- )
36+ val clsToRun = tryToInitializeClass(objectName).getOrElse(throw new ClassNotFoundException (objectName))
9137 val method = clsToRun.getMethod(" main" , classOf [Array [String ]])
92- if (! Modifier .isStatic(method.getModifiers))
93- throw new NoSuchMethodException (objectName + " .main is not static" )
94-
95- try asContext(method.invoke(null , Array (arguments.toArray: AnyRef ): _* )) // !!! : AnyRef shouldn't be necessary
38+ if ! Modifier .isStatic(method.getModifiers) then
39+ throw new NoSuchMethodException (s " $objectName.main is not static " )
40+ try asContext(method.invoke(null , Array (arguments.toArray: AnyRef ): _* ))
9641 catch unwrapHandler({ case ex => throw ex })
9742 }
9843
99- @ tailrec
100- def unwrapThrowable (x : Throwable ): Throwable = x match {
44+ @ tailrec private def unwrapThrowable (x : Throwable ): Throwable = x match {
10145 case _ : InvocationTargetException | // thrown by reflectively invoked method or constructor
10246 _ : ExceptionInInitializerError | // thrown when running a static initializer (e.g. a scala module constructor)
10347 _ : UndeclaredThrowableException | // invocation on a proxy instance if its invocation handler's `invoke` throws an exception
@@ -107,136 +51,27 @@ final class RichClassLoader(private val self: JClassLoader) extends AnyVal {
10751 unwrapThrowable(x.getCause)
10852 case _ => x
10953 }
54+
11055 // Transforms an exception handler into one which will only receive the unwrapped
11156 // exceptions (for the values of wrap covered in unwrapThrowable.)
112- def unwrapHandler [T ](pf : PartialFunction [Throwable , T ]): PartialFunction [Throwable , T ] =
57+ private def unwrapHandler [T ](pf : PartialFunction [Throwable , T ]): PartialFunction [Throwable , T ] =
11358 pf.compose({ case ex => unwrapThrowable(ex) })
114-
115- def show (cl : ClassLoader ): String = {
116- import scala .reflect .Selectable .reflectiveSelectable
117-
118- @ tailrec
119- def isAbstractFileClassLoader (clazz : Class [_]): Boolean = {
120- if (clazz == null ) return false
121- if (clazz == classOf [AbstractFileClassLoader ]) return true
122- isAbstractFileClassLoader(clazz.getSuperclass)
123- }
124- def inferClasspath (cl : ClassLoader ): String = cl match {
125- case cl : java.net.URLClassLoader if cl.getURLs != null =>
126- (cl.getURLs mkString " ," )
127- case cl if cl != null && isAbstractFileClassLoader(cl.getClass) =>
128- cl.asInstanceOf [{val root : AbstractFile }].root.canonicalPath
129- case null =>
130- val loadBootCp = (flavor : String ) => scala.util.Properties .propOrNone(flavor + " .boot.class.path" )
131- loadBootCp(" sun" ) orElse loadBootCp(" java" ) getOrElse " <unknown>"
132- case _ =>
133- " <unknown>"
134- }
135- cl match {
136- case null => s " primordial classloader with boot classpath [ ${inferClasspath(cl)}] "
137- case _ => s " $cl of type ${cl.getClass} with classpath [ ${inferClasspath(cl)}] and parent being ${show(cl.getParent)}"
138- }
139- }
14059}
14160
14261object RichClassLoader {
14362 implicit def wrapClassLoader (loader : ClassLoader ): RichClassLoader = new RichClassLoader (loader)
14463}
14564
146- /** A wrapper around java.lang.ClassLoader to lower the annoyance
147- * of java reflection.
148- */
149- trait ScalaClassLoader extends JClassLoader {
150- private def wrap = new RichClassLoader (this )
151- /** Executing an action with this classloader as context classloader */
152- def asContext [T ](action : => T ): T = wrap.asContext(action)
153-
154- /** Load and link a class with this classloader */
155- def tryToLoadClass [T <: AnyRef ](path : String ): Option [Class [T ]] = wrap.tryToLoadClass[T ](path)
156- /** Load, link and initialize a class with this classloader */
157- def tryToInitializeClass [T <: AnyRef ](path : String ): Option [Class [T ]] = wrap.tryToInitializeClass(path)
158-
159- /** Create an instance of a class with this classloader */
160- def create (path : String ): AnyRef = wrap.create(path)
161-
162- /** Create an instance with ctor args, or invoke errorFn before throwing. */
163- def create [T <: AnyRef : ClassTag ](path : String , errorFn : String => Unit )(args : AnyRef * ): T =
164- wrap.create[T ](path, errorFn)(args : _* )
165-
166- /** The actual bytes for a class file, or an empty array if it can't be found. */
167- def classBytes (className : String ): Array [Byte ] = wrap.classBytes(className)
168-
169- /** An InputStream representing the given class name, or null if not found. */
170- def classAsStream (className : String ) = wrap.classAsStream(className)
171-
172- /** Run the main method of a class to be loaded by this classloader */
173- def run (objectName : String , arguments : Seq [String ]): Unit = wrap.run(objectName, arguments)
174- }
175-
176-
177- /** Methods for obtaining various classloaders.
178- * appLoader: the application classloader. (Also called the java system classloader.)
179- * extLoader: the extension classloader.
180- * bootLoader: the boot classloader.
181- * contextLoader: the context classloader.
182- */
18365object ScalaClassLoader {
184- /** Returns loaders which are already ScalaClassLoaders unaltered,
185- * and translates java.net.URLClassLoaders into scala URLClassLoaders.
186- * Otherwise creates a new wrapper.
187- */
188- implicit def apply (cl : JClassLoader ): ScalaClassLoader = cl match {
189- case cl : ScalaClassLoader => cl
190- case cl : JURLClassLoader => new URLClassLoader (cl.getURLs.toSeq, cl.getParent)
191- case _ => new JClassLoader (cl) with ScalaClassLoader
192- }
193- def contextLoader = apply(Thread .currentThread.getContextClassLoader)
194- def appLoader = apply(JClassLoader .getSystemClassLoader)
195- def setContext (cl : JClassLoader ) = Thread .currentThread.setContextClassLoader(cl)
196-
197- class URLClassLoader (urls : Seq [URL ], parent : JClassLoader )
198- extends JURLClassLoader (urls.toArray, parent)
199- with ScalaClassLoader
200- with HasClassPath {
201- private [this ] var classloaderURLs : Seq [URL ] = urls
202- def classPathURLs : Seq [URL ] = classloaderURLs
66+ def setContext (cl : ClassLoader ) = Thread .currentThread.setContextClassLoader(cl)
20367
204- /** Override to widen to public */
205- override def addURL (url : URL ) = {
206- classloaderURLs :+= url
207- super .addURL(url)
208- }
209- override def close (): Unit = {
210- super .close()
211- classloaderURLs = null
212- }
213- }
214-
215- def fromURLs (urls : Seq [URL ], parent : ClassLoader = null ): URLClassLoader = {
216- new URLClassLoader (urls, if (parent == null ) bootClassLoader else parent)
217- }
68+ def fromURLsParallelCapable (urls : Seq [URL ], parent : ClassLoader = null ): URLClassLoader =
69+ new URLClassLoader (urls.toArray, if parent == null then bootClassLoader else parent)
21870
219- def fromURLsParallelCapable (urls : Seq [URL ], parent : ClassLoader = null ): JURLClassLoader = {
220- new JURLClassLoader (urls.toArray, if (parent == null ) bootClassLoader else parent)
221- }
222-
223- /** True if supplied class exists in supplied path */
224- def classExists (urls : Seq [URL ], name : String ): Boolean =
225- (fromURLs(urls) tryToLoadClass name).isDefined
226-
227- /** Finding what jar a clazz or instance came from */
228- def originOfClass (x : Class [_]): Option [URL ] =
229- Option (x.getProtectionDomain.getCodeSource) flatMap (x => Option (x.getLocation))
230-
231- @ sharable private [this ] val bootClassLoader : ClassLoader = {
232- if (! scala.util.Properties .isJavaAtLeast(" 9" )) null
233- else {
234- try {
71+ @ sharable private [this ] val bootClassLoader : ClassLoader =
72+ if scala.util.Properties .isJavaAtLeast(" 9" ) then
73+ try
23574 MethodHandles .lookup().findStatic(classOf [ClassLoader ], " getPlatformClassLoader" , MethodType .methodType(classOf [ClassLoader ])).invoke().asInstanceOf [ClassLoader ]
236- } catch {
237- case _ : Throwable =>
238- null
239- }
240- }
241- }
75+ catch case _ : Throwable => null
76+ else null
24277}
0 commit comments