Java 9, compatibility issue with ClassLoader.getSystemClassLoader

The following code adds a jar file to the build path, it works fine with Java 8. However, it throws an exception with Java 9, the exception is related to casting to URLClassLoader. Any ideas how this can be solved? the optimal solution will edit it to work with Java 8 and 9.

private static int AddtoBuildPath(File f) {
    try {
        URI u = f.toURI();
        URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
        Class<URLClassLoader> urlClass = URLClassLoader.class;
        Method method = urlClass.getDeclaredMethod("addURL", URL.class);
        method.setAccessible(true);
        method.invoke(urlClassLoader, u.toURL());
    } catch (NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException | MalformedURLException | IllegalAccessException ex) {
        return 1;
    }

    return 0;
}
+8
source share
5 answers

You are faced with the fact that the system class loader is no longerURLClassLoader . As indicated in the ClassLoader::getSystemClassLoaderreturn value ClassLoader::getSystemClassLoader, this was an implementation detail, although one for which the ClassLoader::getSystemClassLoaderamount of code.

, . , Java 9, .

. , , , . Java 9, - .

+6

. , , ,

private static int AddtoBuildPath(File f)

. , , : 1) , ClassLoader.getSystemClassLoader() URLClassLoader - , 2) , addURL , , .

, URL " Class.forName ", , (Java 8–10) :

1) , URL- , addURL

public class MyClassloader extends URLClassLoader {

    public MyClassloader(URL[] urls, ClassLoader parent) {
        super(urls, parent);
    }

    public void addURL(URL url) {
        super.addURL(url);
    }
}

2) ()/app )

private final MyClassloader classLoader;

classLoader = new MyClassloader(new URL[0], this.getClass().getClassLoader());

. . , classLoader , this.getClass().getClassLoader() .

3) ():

File file = new File(path);
if(file.exists()) {
    URL url = file.toURI().toURL();
    classLoader.addURL(url);
}

4)

cls = Class.forName(name, true, classLoader);

. ( ), , , , . : ClassPathB , ClassPathB ClassPathA classLoader, ClassPathB , ClassPathA . , ClassPathB , classLoader, ClassPathA ClassPathB.

5)

setContextClassLoader(classLoader)

, getContextClassLoader.

+3

. :

Class.forName("nameofclass", true, new URLClassLoader(urlarrayofextrajarsordirs));

, , :

:

java.util.ServiceLoader ClassLoader Thread.currentThread(). setContextClassLoader ( );

java.sql.DriverManager ClassLoader, ThreadLoader. , Class.forName( "drivername", true, new URLClassLoader (urlarrayofextrajarsordirs).newInstance();

javax.activation ClassLoader ( javax.mail).

+2

, , JVM , , :

object ClassloaderHelper {
  def getURLs(classloader: ClassLoader) = {
    // jdk9+ need to use reflection
    val clazz = classloader.getClass

    val field = clazz.getDeclaredField("ucp")
    field.setAccessible(true)
    val value = field.get(classloader)

    value.asInstanceOf[URLClassPath].getURLs
  }
}

val classpath =
  (
    // jdk8
    // ClassLoader.getSystemClassLoader.asInstanceOf[URLClassLoader].getURLs ++
    // getClass.getClassLoader.asInstanceOf[URLClassLoader].getURLs

    // jdk9+
    ClassloaderHelper.getURLs(ClassLoader.getSystemClassLoader) ++
    ClassloaderHelper.getURLs(getClass.getClassLoader)
  )

$ AppClassLoader , JVM:

--add-opens java.base/jdk.internal.loader=ALL-UNNAMED
+1

.

String pathSeparator = Syste.getProperty("path.separator"); String [] classPathEntries = System.getProperty("java.class.path").split(pathSeparator);

https://blog.codefx.org/java/java-11-migration-guide/#Casting-To-URL-Class-Loader

0

Source: https://habr.com/ru/post/1687329/


All Articles