Подключение файла в JAR через Netbeans

455
22 августа 2017, 11:58

Пользуюсь средой разработки NetBeans. Собираю с помощью Ant.

Проблема заключается вот в чем: Например у меня есть какой-то проект с библиотеками в папке lib и некоторыми файлами в папке src. Объекты создаваемые в этом проекте используют данные библиотеки и файлы. Далее если я собираю данный проект в jar и кладу в библиотеку другого проекта, а потом использую объекты классов из данного jar то выпадает ислючение, что не хватает библиотек, либо файла по данному пути не существует. Соответственно, если добавить данные библиотеки и файлы в новый проект, то все работает. Но в jar они есть!!! Как сделать так чтобы объекты классов создаваемых из jar использовали данные ресурсы из своего jar?

Вот абстрактный пример: Проект "А" из которого мы собираем jar и котором лежит файл hello.txt

package inner.ru;
import java.io.File;
public class Check {
     private final File file = new File("src//inner//file//hello.txt");
    public void print() {
        System.out.println(file.exists());
    }
}

Проект "B" в который в библиотеку мы кладем данный jar

 package external.main;
 import inner.ru.Check;
 public class Main {
     /**
     * @param args the command line arguments
     */
     public static void main(String[] args) {
         Check check = new Check();
         check.print();
     }
}

Соответственно если во второй проект положить файл hello.txt, то получим true, но он уже лежит в первом проекте, и мне надо, чтобы он брал его именно оттуда.

Answer 1

Вы обращаетесь к файлу по относительному пути:

private final File file = new File("src//inner//file//hello.txt");

т.е. Вы ссылаетесь на файл, который лежит в папке src\inner\file относительно папки, в которой запущено приложение, а не к файлу, который запакован в JAR.

Когда Вы запускаете первый проект из Netbeans, он устанавливает текущую папку в корневой каталог проекта и код находит файл в папке исходников. Если Вы вытащите собранный JAR, перенесете его в отдельную папку и запустите его вручную там, то произойдет ошибка, т.к. папки src уже не будет. По той же причине ошибка возникает при запуске из второго проекта (файла нет в исходниках).

Возможные решения:

  1. Указать абсолютный путь.

Вынести файл из проектов вообще и обращаться к нему по абсолютному пути (c:\\Projects....\hello.txt). В этом случае добавлять файл в JAR не нужно. При переносе скажем, на другую машину, файл потребуется носить отдельно, но так он будет доступен всем проектам.

  1. Обращаться к файлу в JAR

Если файл находится в пакете inner.file то можно обращаться к запакованному файлу как к ресурсу. Например, вот так можно вывести содержимое файла:

public void print() {
    try (final InputStream stream = Check.class.getResourceAsStream("/inner/file/hello.txt")) {
        java.util.Scanner s = new java.util.Scanner(stream);
        while (s.hasNext()) {
            System.out.println(s.nextLine());
        }
    } catch (IOException ex) {
        System.out.println("File doesn't exist");
    }
}    

Здесь обращение идет именно к файлу, запакованному в JAR и, соответственно, файл будет доступен при использовании из других проектов.

Дополнение по библиотекам:

Та же проблема возникает с библиотеками. Используемые библиотеки не собираются в результирующий JAR файл. Соответственно, если проект inner использует библиотеку dependency.jar, которая не включена в проект external то при обращении к методам inner, которые зависят от dependency будут выброшены исключения.

Возможные решения:

  1. Переносить вместе с JAR-файлом все его библиотеки.

Т.е. если external использует inner, то в него нужно добавить dependency.jar. При таком точечном подходе возможно более гибкое использование библиотек. Например, external может использовать более новую версию dependency, в этом случае может быть ненужно таскать за inner старые версии.

Посмотрите также на системы управления зависимостями: например, Maven или Ivy. Они существенно упрощают работу с библиотеками при сборке.

  1. Собрать все зависимости в один JAR.

Можно также собрать inner таким образом, чтобы в одном JAR содержались все необходимые библиотеки.

Сделать это можно так:

  1. Открыть файл build.xml — это скрипт сборки Ant, который находится в корне проекта. В Netbeans он отображается в окне «Файлы».
  2. Добавить в конец скрипта следующую цель:
<target name="package-for-store" depends="jar">
    <!-- Замените MyJarName на имя, соответствуюее Вашему JAR
    -->
    <property name="store.jar.name" value="MyJarName"/>

    <!-- don't edit below this line -->
    <property name="store.dir" value="store"/>
    <property name="store.jar" value="${store.dir}/${store.jar.name}.jar"/>
    <echo message="Packaging ${application.title} into a single JAR at ${store.jar}"/>
    <delete dir="${store.dir}"/>
    <mkdir dir="${store.dir}"/>
    <jar destfile="${store.dir}/temp_final.jar" filesetmanifest="skip">
        <zipgroupfileset dir="dist" includes="*.jar"/>
        <zipgroupfileset dir="dist/lib" includes="*.jar"/>
        <manifest>
            <attribute name="Main-Class" value="${main.class}"/>
        </manifest>
    </jar>
    <zip destfile="${store.jar}">
        <zipfileset src="${store.dir}/temp_final.jar"
        excludes="META-INF/*.SF, META-INF/*.DSA, META-INF/*.RSA"/>
    </zip>
    <delete file="${store.dir}/temp_final.jar"/>
</target>
  1. После этого раскрыть build.xml и найти цель «package-for-store».
  2. Нажать на цель правой кнопкой и запустить ее.
  3. В корне проекта в папке store должен появиться JAR, с упакованными в него зависимостями. Его можно использовать в других проектах.

Смотрите также:

  • Урок со скриншотами из которого взят код выше — Use NetBeans IDE 6.7 to Combine JAR Files Into a Single JAR File
  • Обсуждение в английской версии — Netbeans Export to Jar, include all library files
Answer 2

Я при использовании Ant добавляю зависимые библиотеки и в один и в другой проект, то есть:
есть библиотека Y,
есть проект A,
который использует проект B,
который в свою очередь использует Y.
Я добавляю Y и к A и к B.
Вся фишка в том, как именно происходит сборка, например, если вы используете настройки Ant Netbeans по умолчанию, то зависимые библиотеки складываются в папку lib относительно основного jar файла и так прописываются в манифесте.
Если же вы подключаете другой проект как зависимый, jar файл этого проекта просто указывается библиотекой и так же помещается в папку lib.
Соответственно в манифесте проекта B указывается lib как папка с библиотеками для него, но этой папки нет, так как сам подключаемый jar проекта B уже лежит в lib. Думаю, если Вам не хочется дублировать библиотеки, то зависимый проект B стоит собирать как один jar файл с упаковкой библиотек в него.

READ ALSO
Как я могу получить int из string?

Как я могу получить int из string?

Есть такой кусочек кодаПо bluetooth я получаю строку с двумя переменными, разделяю их по пайпу, потом каждую переменную по отдельности показываю...

251
Как правильно должен работать ssl?

Как правильно должен работать ssl?

Добрый день! Есть сервер и клиент, написанные на джавеКлиент общедоступен

257
Есть ли наследование в моделировании? [требует правки]

Есть ли наследование в моделировании? [требует правки]

От АнтиООП-шников часто можно услышать: "В моделировании никакого наследования нет!", я уже слышал эта два разаА откуда звон то?

247
Актуален ли StringBuilder в 2017?

Актуален ли StringBuilder в 2017?

С давних пор есть мнение, что конкатинирвать строки в Java нужно при помощи StringBuilder, но с появлением Java 8 появилось много статей о том, что можно...

212