Добавить jar в classpath во время выполнения под java 9

До для добавления внешней банки для пути к классам во время выполнения программным способом:

URLClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Method method = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{URL.class});
method.invoke(sysloader, new Object[]{file.toURI().toURL()});

Теперь с java9 возникает проблема:

Исключение в потоке "main" java.lang.ClassCastException:     java.base/jdk.internal.loader.ClassLoaders $AppClassLoader     не может быть добавлено в java.base/java.net.URLClassLoader

URLClassLoader больше не работает в Java 9. Что теперь делать в jdk9 для добавления внешнего бана в путь к классам во время выполнения программно?

Ответ 1

Примечания к выпуску JavaSE9 читаются примерно так же:

Загрузчик класса приложения больше не является экземпляром java.net.URLClassLoader (деталь реализации, которая никогда не была указана в предыдущих выпусках).

Код, который предполагает, что ClassLoader::getSytemClassLoader возвращает объект URLClassLoader, необходимо будет обновить.

Обратите внимание, что Java SE и JDK не предоставляют API для приложений или библиотек для динамического расширения пути к классам во время выполнения.

Кроме того, когда требуется расширенный путь к классу, можно использовать

Class<?> clazz = Class.forName("nameofclass", true, new URLClassLoader(urlarrayofextrajarsordirs));

как предложено в этой теме от Oracle. Это идет с оговорками:

  • java.util.ServiceLoader использует поток контекста ClassLoader Thread.currentThread(). setContextClassLoader (specialloader);

  • java.sql.DriverManager вызывающий класс ClassLoader, а не поток ClassLoader. Создать драйвер напрямую, используя Class.forName("drivername", true, new URLClassLoader(urlarrayofextrajarsordirs).newInstance();

  • javax.activation использует контекст потока ClassLoader (важно для javax.mail).

Ответ 2

Наман ответ не является правильной заменой того, что вы ищете. Правильный способ добавить jar в путь к классам в Java 9 и выше - использовать appendToSystemClassLoaderSearch(JarFile jarfile) Java Instrumentation.

Сначала вам нужно будет добавить класс агента в ваш файл MANIFEST.MF.

Launcher-Agent-Class: com.yourpackage.Agent

Затем добавьте свой агент. Приведенный ниже пример позволит вам вызвать Agent.addClassPath(File f) чтобы добавить Jar- Agent.addClassPath(File f) в classpath в Java 8 и 9+.

public class Agent {
    private static Instrumentation inst = null;

    // The JRE will call method before launching your main()
    public static void agentmain(final String a, final Instrumentation inst) {
        Agent.inst = inst;
    }

    public static boolean addClassPath(File f) {
        ClassLoader cl = ClassLoader.getSystemClassLoader();

        try {
            // If Java 9 or higher use Instrumentation
            if (!(cl instanceof URLClassLoader)) {
                inst.appendToSystemClassLoaderSearch(new JarFile(f));
                return;
            }

            // If Java 8 or below fallback to old method
            Method m = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
            m.setAccessible(true);
            m.invoke(cl, (Object)f.toURI().toURL());
        } catch (Throwable e) { e.printStackTrace(); }
    }

}