Я бы согласился с комментариями по этому вопросу. Исходя из предоставленного вами кода, может показаться, что вы получаете ошибку из-за того, что файлы JAR находятся не там, где вы ожидаете их найти. Как уже упоминалось @Andrew, вы не проверяете наличие файла в вашем методе addJarToClasspath. В результате, если файл не существует, вы получите исключение ClassNotFound, как вы видите. Я проверил эту проблему, взяв логику ClassLoader и передав ей действительный и недействительный JAR. Когда был указан правильный JAR / путь, ClassLoader загрузил класс, как и ожидалось. Когда был указан неверный JAR / путь, я получил указанную вами ошибку. URLClassLoader не генерирует исключение, если указан URL-адрес, который не указывает на допустимый файл.
Чтобы проверить сценарий, распечатайте путь к полному пути вашего файла и посмотрите, подходит ли он для среды выполнения.
Редактировать
Похоже, что даже если вы переопределите системный ClassLoader, виртуальная машина все равно будет использовать значение по умолчанию
sun.misc.Launcher$AppClassLoader
для загрузки некоторых классов. В моем тестировании это включает в себя классы, на которые ссылаются из основного приложения. Я уверен, что есть причина для этого процесса, однако я не могу установить это в настоящее время. Я предложил вам несколько решений:
- Используйте сценарий для обнаружения среды и соответственно укажите путь к классу. Это, пожалуй, самое простое решение, но вы можете или не можете принять его в зависимости от ваших конкретных требований.
- Подобно тому, что было упомянуто в других ответах, специально загрузите и запустите ваше приложение, используя ваш собственный ClassLoader. Это не означает создание единого класса, который будет загружен, а затем вызовет ваше приложение. Это означает, что любой класс, который должен взаимодействовать с динамически загружаемыми библиотеками
swt
, и любые классы, которые должны ссылаться на классы вашего приложения, должны быть загружены из вашего пользовательского ClassLoader. Любые зависимости приложения, такие как log4j и т. Д., Могут ссылаться на приложение по умолчанию ClassLoader. Вот пример того, как это будет работать:
JAR 1 (launcher.jar):
public class AppLauncher {
public static void main(String… args) throws Exception {
ClassLoader loader = initClassLoader();
Class<?> mpClass = loader.loadClass("mp.MyProgram");
// using Runnable as an example of how it can be done
Runnable mpClass = (Runnable) mpClass.newInstance();
}
public static ClassLoader initClassLoader() {
// assuming still configured as system classloader, could also be initialized directly
LibraryLoader loader = (LibraryLoader) ClassLoader.getSystemClassLoader();
// add the main application jar to the classpath.
// You may want to dynamically determine this value (lib folder) or pass it in as a parameter
loader.addJarToClasspath("myapp.jar");
String architecture = System.getProperty("os.arch");
try {
if (architecture.contains("64")) {
loader.addJarToClasspath("swt-3.6.1-win32-win32-x86_64.jar");
} else {
loader.addJarToClasspath("swt-3.6.1-win32-win32-x86.jar");
}
Class.forName("org.eclipse.swt.graphics.Point", false, loader);
org.eclipse.swt.graphics.Point pt = new org.eclipse.swt.graphics.Point(0, 0);
} catch (Exception exception) {
exception.printStackTrace();
System.out.println("Could not load SWT library");
System.exit(1);
}
return loader;
}
JAR 2 (myapp.jar): Включает все классы, которые зависят от swt
public class MyProgram implements Runnable {
//…
public void run() {
// perform application execution
// this logic should now work
org.eclipse.swt.graphics.Point pt = new org.eclipse.swt.graphics.Point(0,0);
}
}
Класс AppLauncher
будет выполняться виртуальной машиной, а остальная часть вашего приложения не будет включена в исполняемый Jar.
java -Djava.system.class.loader = test.LibraryLoader -cp <зависимые банки>: launcher.jar mp.AppLauncher
Я вижу, что были обновления для других ответов. Поскольку я уже напечатал вышеупомянутые комментарии, я решил, что я все еще должен опубликовать его для вашего ознакомления.