Как заставить java ServiceLoader работать в приложении модуля NetBeans 6.9 - PullRequest
3 голосов
/ 29 июня 2010

У меня проблемы с использованием java ServiceLoader в модульном приложении NetBeans.Вот что я пытаюсь сделать (и это работает в обычном Java-приложении в Eclipse):

У меня есть interface.jar, который объявляет интерфейс.И у меня есть файл реализаций.jar, в котором есть несколько реализаций этого интерфейса, все они указаны в файле spi / META-INF / services / my.package.name.MyInteface (этот файл находится в файле реализаций.jar).

У меня также есть класс PracticeHandler (в еще одном handler.jar), который имеет следующий метод для загрузки всех реализаций:

private static List<MyInterface<?>> loadAllImplementations() {
    List<MyInterface<?>> foundImplementations = Lists.newArrayList();
    try {
        for (MyInterface implementation : ServiceLoader.load(MyInterface.class)) {
            foundImplementations.add(implementation);
        }
    } catch (ServiceConfigurationError error) {
        system.out.println("Exception happened");
    }
    return foundImplementations;
}

Этот код возвращает все реализации в обычном приложении Eclipse (foundImplementations.size()> 0).

Однако в NetBeans он ничего не может найти (foundImplementations.size () == 0).

Подробнее:
У меня есть источникприложение модуля NetBeans (с открытым исходным кодом, не написанное мной), которое мне необходимо расширить с помощью некоторых реализаций MyInterface.Интерфейс.jar, Implementations.jar и Handler.jar создаются в Eclipse и являются частью другого приложения.

В NetBeans я открыл модуль, который должен использовать новые имплементации, и добавил все свои 3 банки в качестве внешних библиотек (NetBeans скопировал их в свою папку ext, которую я не хочу, но могу »ничего не поделать - я хочу, чтобы они были в другой папке myext, но это уже другая история).Затем я перестроил все и попытался использовать одну из моих реализаций, но она не была найдена ... Код, который получает реализацию, находится в классе ImplementHandler и выглядит так:

public static final <T> MyInteface<T> getByName(String name) {
    for (MyInteface implementation : loadAllImplementations()) {
        if (implementation.getName().equals(name)) {
            return implementation;
        }
    }

    throw new IllegalArgumentException("Unable to find MyInterface class for: " + name);
}

Я получил свое исключение "Не удалось найти класс MyInteface для: myImplementationName "...

Мои знания о NetBeans очень ограничены, и мне было интересно, есть ли что-то еще, что мне нужно сделать, чтобы это работало?

Ответы [ 3 ]

2 голосов
/ 06 июля 2011

Чтобы работать, вам нужно заставить Netbeans создать эту подпапку сервисов внутри META-INF.Это очень легко сделать, но информация легко доступна.

Чтобы добавить что-то в META-INF, вам нужно создать папку с таким именем в вашей папке src / (source directory [spi?]),В этом случае вам также понадобится папка services, и в ней создайте текстовый файл с тем же полным именем, что и интерфейс службы.В конце вы должны иметь следующую структуру: src / META-INF / services / my.package.MyInterface.

Наконец, содержимое этого файла [my.package.MyInterface] должно содержать список всех классов реализации (по одному наline).

При такой настройке Netbeans создаст соответствующий файл jar при создании приложения.

Посмотрите этот пример ServiceLoader .Это полный пример, хотя он не объясняет интеграцию Netbeans, которую я только что описал.

0 голосов
/ 12 июля 2010

Я сдался и заменил ClassLoader на JSPF . Это работает «из коробки», и мне не нужно знать о внутренностях сторонней программы, написанной как модуль NetBeans, и о том, как это влияет на путь к классам, данный загрузчикам классов.

0 голосов
/ 02 июля 2010

ServiceLoader.load (Class) использует загрузчик класса контекста текущего потока для загрузки всех реализаций. Может случиться так, что в вашем случае ваши классы реализации в вашем jar-файле (creation.jar) не находятся в пути к классам загрузчика классов.

Возможно, вам придется попробовать разные подходы для этого:

  • Возможно, вам понадобятся все файлы jar в пути к классам модуля netbeans или,
  • Возможно, вам потребуется создать загрузчик классов (возможно, URLClassLoader с этими jar-файлами в своем пути к классам), использовать ServiceLoader.load(Class, ClassLoader) и передать этот загрузчик классов.
  • Есть еще одна опция, которую вы можете попробовать, но я не уверен в этом: спецификация jar-файла позволяет вам указать атрибут манифеста Class-Path, к которому вы можете добавить запись "creation.jar". Подробнее здесь

Скорее всего, handler.jar и Implementations.jar не загружаются одним и тем же загрузчиком классов. Также вы можете посмотреть, почему ваши файлы попадают в папку ext.

Надеюсь, это поможет.

Edit:

  • Также попробуйте вызвать ServiceLoader.load(Class, null), который использует загрузчик класса System (тот, который запустил приложение). Вероятно, этот загрузчик классов сможет найти классы в jar-файлах, расположенных в каталоге ext.
...