1
1
package dotty .tools
2
2
package runner
3
3
4
- import java .lang .invoke .{MethodHandles , MethodType }
5
-
6
4
import scala .language .implicitConversions
7
- import java .lang .{ClassLoader => JClassLoader }
5
+
6
+ import java .lang .ClassLoader
7
+ import java .lang .invoke .{MethodHandles , MethodType }
8
8
import 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 }
11
11
12
+ import scala .annotation .internal .sharable
12
13
import scala .annotation .tailrec
13
14
import 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
21
15
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 {
27
17
/** Executing an action with this classloader as context classloader */
28
- def asContext [T ](action : => T ): T = {
18
+ private def asContext [T ](action : => T ): T = {
29
19
val saved = Thread .currentThread.getContextClassLoader
30
20
try { ScalaClassLoader .setContext(self) ; action }
31
21
finally ScalaClassLoader .setContext(saved)
32
22
}
33
23
34
24
/** Load and link a class with this classloader */
35
25
def tryToLoadClass [T <: AnyRef ](path : String ): Option [Class [T ]] = tryClass(path, initialize = false )
26
+
36
27
/** Load, link and initialize a class with this classloader */
37
28
def tryToInitializeClass [T <: AnyRef ](path : String ): Option [Class [T ]] = tryClass(path, initialize = true )
38
29
39
30
private def tryClass [T <: AnyRef ](path : String , initialize : Boolean ): Option [Class [T ]] =
40
31
catching(classOf [ClassNotFoundException ], classOf [SecurityException ]) opt
41
32
Class .forName(path, initialize, self).asInstanceOf [Class [T ]]
42
33
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
-
86
34
/** Run the main method of a class to be loaded by this classloader */
87
35
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))
91
37
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 ): _* ))
96
41
catch unwrapHandler({ case ex => throw ex })
97
42
}
98
43
99
- @ tailrec
100
- def unwrapThrowable (x : Throwable ): Throwable = x match {
44
+ @ tailrec private def unwrapThrowable (x : Throwable ): Throwable = x match {
101
45
case _ : InvocationTargetException | // thrown by reflectively invoked method or constructor
102
46
_ : ExceptionInInitializerError | // thrown when running a static initializer (e.g. a scala module constructor)
103
47
_ : 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 {
107
51
unwrapThrowable(x.getCause)
108
52
case _ => x
109
53
}
54
+
110
55
// Transforms an exception handler into one which will only receive the unwrapped
111
56
// 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 ] =
113
58
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
- }
140
59
}
141
60
142
61
object RichClassLoader {
143
62
implicit def wrapClassLoader (loader : ClassLoader ): RichClassLoader = new RichClassLoader (loader)
144
63
}
145
64
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
- */
183
65
object 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)
203
67
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)
218
70
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
235
74
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
242
77
}
0 commit comments