summaryrefslogtreecommitdiff
path: root/main/core/src/mill/util/ClassLoader.scala
blob: 17268fb08908c3cc05ad1c63017d465cc3af1e81 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package mill.util

import java.net.{URL, URLClassLoader}

import ammonite.ops._
import io.github.retronym.java9rtexport.Export

object ClassLoader {

  def create(urls: Seq[URL], parent: java.lang.ClassLoader)(
      implicit ctx: Ctx.Home): URLClassLoader = create(urls, parent, _ => None)

  def create(urls: Seq[URL],
             parent: java.lang.ClassLoader,
             customFindClass: String => Option[Class[_]])(
      implicit ctx: Ctx.Home): URLClassLoader = {
    new URLClassLoader(
      makeUrls(urls).toArray,
      refinePlatformParent(parent)
    ) {
      override def findClass(name: String): Class[_] = {
        if (name.startsWith("com.sun.jna")) getClass.getClassLoader.loadClass(name)
        else customFindClass(name).getOrElse(super.findClass(name))
      }
    }
  }

  /**
    *  Return `ClassLoader.getPlatformClassLoader` for java 9 and above, if parent class loader is null,
    *  otherwise return same parent class loader.
    *  More details: https://docs.oracle.com/javase/9/migrate/toc.htm#JSMIG-GUID-A868D0B9-026F-4D46-B979-901834343F9E
    *
    *  `ClassLoader.getPlatformClassLoader` call is implemented via runtime reflection, cause otherwise
    *  mill could be compiled only with jdk 9 or above. We don't want to introduce this restriction now.
    */
  private def refinePlatformParent(parent: java.lang.ClassLoader): ClassLoader = {
    if (ammonite.util.Util.java9OrAbove) {
      if (parent == null)
        classOf[ClassLoader]
          .getMethod("getPlatformClassLoader")
          .invoke(null)
          .asInstanceOf[ClassLoader]
      else parent
    } else {
      parent
    }
  }

  private def makeUrls(urls: Seq[URL])(implicit ctx: Ctx.Home): Seq[URL] = {
    if (ammonite.util.Util.java9OrAbove) {
      urls :+ Export.rtAt(ctx.home.toIO).toURI.toURL
    } else {
      urls
    }
  }
}