SPI + JDK 9 + module-info.java

Я экспериментирую с SPI на JDK 9. Весь пример работает на JDK 9 без "module-info.java". После добавления "module-info.java" ServiceLocator не находит реализующий класс. Я запутался и не могу найти работающий пример SPI в модульном проекте JDK 9.

Итак, мой пример проекта выглядит так:

/spidemo
├── apiModule
│   ├── pom.xml
│   └── src
│       └── main
│           └── java
│               ├── eu
│               │   └── com
│               │       └── example
│               │           └── text
│               │               └── spi
│               │                   └── TextAPI.java
│               └── module-info.java
├── applicationB
│   ├── pom.xml
│   └── src
│       └── main
│           ├── java
│           │   └── eu
│           │       └── com
│           │           └── example
│           │               └── spi
│           │                   └── b
│           │                       └── application
│           │                           └── DemoB.java
│           └── module-info.java
├── applicationCommon
│   ├── pom.xml
│   └── src
│       └── main
│           └── java
│               ├── eu
│               │   └── com
│               │       └── example
│               │           └── spi
│               │               └── application
│               │                   └── TextAPIProvider.java
│               └── module-info.java
├── implementationB
│   ├── pom.xml
│   └── src
│       └── main
│           ├── java
│           │   └── eu
│           │       └── com
│           │           └── example
│           │               └── implb
│           │                   └── text
│           │                       └── TextB.java
│           ├── module-info.java
│           └── resources
│               └── META-INF
│                   └── services
│                       └── eu.com.example.text.spi.TextAPI

Я ввел интерфейс:

package eu.com.example.text.spi;
public interface TextAPI {
    String getHelloWorldText();
}

Этот интерфейс реализован:

package eu.com.example.implb.text;
import eu.com.example.text.spi.TextAPI;
public class TextB implements TextAPI { 
    public String getHelloWorldText() {
        return "Text from B implementation";
    }
}

Реализация ищется по коду, похожему на:

package eu.com.example.spi.application;
import eu.com.example.text.spi.DefaultTextAPI;
import eu.com.example.text.spi.TextAPI;
import java.util.ServiceLoader;
public class TextAPIProvider {

    public static TextAPI getProvider(String providerName) {
        ServiceLoader<TextAPI> serviceLoader = ServiceLoader.load(TextAPI.class);
        for (TextAPI provider : serviceLoader) {
            String className = provider.getClass().getName();
            if (providerName.equals(className)) {
                return provider;
            }
        }
        throw new RuntimeException(providerName + " provider is not found!");
    }
}

А теперь самое интересное. Когда я выполняю класс ниже без:

  • /implementationB/src/main/java/module-info.java
  • /applicationB/src/main/java/module-info.java

затем класс реализации найден и текст распечатан.

package eu.com.example.spi.b.application;
import eu.com.example.spi.application.TextAPIProvider;
public class DemoB {
    public static void main(String[] args) {
        System.out.println("---> " + TextAPIProvider.getProvider("eu.com.example.implb.text.TextB").getHelloWorldText());
    }
}

После введения этих двух классов "module-info.java" класс реализации не найден ServiceLocator. Содержание /applicationB/src/main/java/module-info.java:

module eu.com.example.applicationB {
    requires eu.com.example.apiModule;
    requires transitive eu.com.example.applicationCommon;
    uses eu.com.example.text.spi.TextAPI;
}

Содержимое /implementationB/src/main/java/module-info.java:

module eu.com.example.implb.text {
    requires eu.com.example.apiModule;
    exports eu.com.example.implb.text;
//    provides eu.com.example.implb.text.TextB with eu.com.example.text.spi.TextAPI;
}

Когда я раскомментирую

provides eu.com.example.implb.text.TextB with eu.com.example.text.spi.TextAPI;

В строке затем возникает ошибка компиляции:

.../implementationB/src/main/java/module-info.java:[7,74] the service implementation type must be a subtype of the service interface type, or have a public static no-args method named "provider" returning the service implementation
.../implementationB/src/main/java/module-info.java:[7,5] service implementation must be defined in the same module as the provides directive

Я пытался изменить имена пакетов, как предлоги ошибок компиляции, но затем я ввел проблемы "разделенного пакета".

Что я должен сделать, чтобы использовать ServiceLocator в полностью модульном JDK 9? Является ли это возможным? Кто-нибудь видел рабочий пример? Код также можно увидеть здесь: https://github.com/RadoslawOsinski/spidemo

2 ответа

Решение

Вы можете перейти на использование:-

provides eu.com.example.text.spi.TextAPI with eu.com.example.implb.text.TextB; 
// you provide a service through its implementation

вместо

provides eu.com.example.implb.text.TextB with eu.com.example.text.spi.TextAPI; 

Службы в документе предоставляют образец вокруг реализации.

Модуль может указывать, что он предоставляет услугу с определенным типом поставщиков услуг. Заявлено использование и with ключевое слово.

синтаксис: предоставляет serviceType с implementationTypes;

(Можно указать несколько типов реализаций в виде списка, разделенного запятыми)

Поэтому в ваш модуль следует добавить следующую инструкцию.

      provides eu.com.example.implb.text.TextB with eu.com.example.text.spi.TextAPI;

ПРИМЕЧАНИЕ : provides не равно exports. Итак, любые другие модули, требующие eu.com.example.implb.text не будет иметь доступа eu.com.example.implb.text.TextB если не экспортирует.

Другие вопросы по тегам