Java Найдите абсолютный путь зависимой банки - PullRequest
0 голосов
/ 16 марта 2020

У меня есть файл Jar, который зависит от другого проекта JAR. Оба представляют собой тонкие банки и находятся в одном месте. 1-й jar содержит файл манифеста, в котором перечисляется второй jar в свойстве class-path.

В первом jar я запускаю второй jar как процесс, использующий класс ProcesBuilder в java. Для этого мне нужен абсолютный путь второй банки. В 1-й банке у меня есть класс XClient. Если я делаю XClient.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath();, я получаю абсолютный путь 1-й баночки. Затем я могу разделить и добавить имя второго фляги (жестко), чтобы построить абсолютный путь

Во втором фляге у меня есть класс XServer, если я делаю

 XServer .class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath();

Исключение его бросков

Я не уверен, что делаю правильный подход, но моя цель очень ясна. Я хотел получить абсолютный путь к зависимой банке.

Пожалуйста, помогите

1 Ответ

1 голос
/ 15 апреля 2020

Я пытался использовать тот же подход (но использовал File file=new File(this.getClass().getProtectionDomain().getCodeSource().toUri()) вместо getPath()), но это может не сработать по-разному:

  1. , когда класс находится внутри jar, объект File указывает вместо jar, в папку, в которой находится jar, поэтому if(file.isFile()) file=file.getParentFile(); необходим для получения каталога вместо jar-файла
  2. , когда jar-файл загружается чем-то отличным от обычного URLClassLoader (последний раз, когда я попытка была еще в 1.8 - и я знаю только, что, поскольку Jigsaw основной загрузчик классов не может быть приведен к URLClassLoader больше), это может вернуть некоторый неопределенный результат, если вообще так, поэтому фактическое поведение зависит от самой настройки системы - которая может затрудняет отладку при использовании в удаленной системе, не находящейся под вашим контролем.
  3. UN C пути (Windows общие ресурсы) сами подвержены ошибкам - добавление еще одного слоя поверх него (java) просто добавьте множество других потенциальных ловушек, которые вы все должны протестировать и отладить - которые часто заканчиваются тем, что вы говорите клиенту, что использовать и как настроить вместо desi Позвольте вашему коду следовать принципу java: «Пиши один раз, компилируй один раз, беги везде» (кстати: это также применимо, даже если вы «монтируете» сетевой ресурс, поэтому вы можете адресовать его по буквам локального диска вместо удаленного). сетевой путь - но это даже вызывает проблемы, когда вы пытаетесь связать две машины, где одна является клоном другой)
  4. , как уже упоминалось в качестве комментария: «это не работает» не является полезным или значимым описанием - если вы получите сообщение об ошибке (в данном случае вы упомянули трассировку стека исключений), отправьте его вместе с кодом, который его создал (если он доступен)

Как я решил свою проблему? Я просто спрашиваю у пользователя каталог / файл с помощью свинга JFileChooser. Да, это не доказательство глупости и, возможно, не лучший способ - но он работает, поскольку свинг все еще поставляется с SE JVM (вместо FX). Если вы хотите найти путь, используйте Class.getResource (), и пусть java сделает всю работу, очень похоже на crypto: не делайте своего.

Помимо всего этого: упомянутый вами "usecase" не требует того, что вы пытаетесь сделать. Вы сказали, что сервер уже находится в пути к классам - поэтому он загружается при запуске, и вы можете получить доступ к классу XServer. Самый простой способ вместо того, чтобы разветвлять другой процесс, это просто запустить его в другом потоке. Если вы знаете, что у класса есть main (манифест server.jar скажет вам), и вы можете получить к нему доступ через classpath, просто сделайте что-то вроде этого:

Thread serverThread=new Thread(new Runnable()
{
    public void run()
    {
        String[] args=Arrays.asList("required", "parameters");
        XServer.main(args);
    }
});
serverThread.start();

Если параметры не требуются, вы можете просто передать пустой массив строк. Поскольку main () не должен выдавать исключения (по крайней мере, не отмеченные), исключение не требуется.

Прежде чем все эти комментарии будут брошены на меня: Да, я очень хорошо знаю о возможных проблемах с таким подходом, как Проблемы с classpath (одно и то же имя класса в том же имени пакета, но в разных версиях), и это может быть более целесообразным, чем попытка выяснить абсолютный путь и запустить процесс fork / sub. Кроме того: запуск другого процесса может потребовать взаимодействия с его потоками (предоставить требуемый ввод в дочерний процесс дочернего процесса и прочитать выходной поток дочернего процесса и поток ошибок - в противном случае разветвленный процесс может «зависнуть», ожидая очистки конвейеров. Это боль в том, чтобы отлаживать подобные проблемы, если это не ваш собственный код, и вы можете подключить к нему профилировщик и отладчик, чтобы выяснить, почему все вдруг перестало работать.

Если вы действительно хотите ( Я не думаю, что есть какое-либо требование, заставляющее «вам нужно») запускать сервер вместе с клиентом, делать это с помощью скрипта запуска за пределами java, но с вещами уровня os.

...