Джерси Hk2 впрыскивает аннотированные классы @Service

На всю жизнь я не могу заставить Джерси с hk2 автоматически обнаруживать аннотированные классы @Service и вводить их. Я пытался следовать всем советам по переполнению стека, документации по джерси и hk2 и все еще не повезло. Я пытаюсь внедрить простой эхо-сервис в ресурс Джерси. Скелет создан из простого веб-приложения maven для Джерси, которое я попытался расширить. Это то, что я до сих пор:

pom.xml

<build>
  <finalName>sandbox</finalName>
  <plugins>
    <plugin>
      <groupId>org.glassfish.hk2</groupId>
      <artifactId>hk2-inhabitant-generator</artifactId>
      <version>2.3.0</version>
      <executions>
        <execution>
          <configuration>
            <verbose>true</verbose>
          </configuration>
          <goals>
            <goal>generate-inhabitants</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>
...
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.glassfish.jersey</groupId>
      <artifactId>jersey-bom</artifactId>
      <version>${jersey.version}</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

<dependencies>
  <dependency>
    <groupId>org.glassfish.jersey.containers</groupId>
    <artifactId>jersey-container-servlet-core</artifactId>
  </dependency>
  <dependency>
    <groupId>org.glassfish.hk2</groupId>
    <artifactId>hk2</artifactId>
    <version>2.3.0</version>
  </dependency>
</dependencies>

web.xml

<servlet>
    <servlet-name>Jersey Web Application</servlet-name>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>jersey.config.server.provider.packages</param-name>
        <param-value>my.package.jerseytest</param-value>
    </init-param>
    <init-param>
        <param-name>javax.ws.rs.Application</param-name>
        <param-value>my.package.jerseytest.application.Application</param-value>
    </init-param>    

    <load-on-startup>1</load-on-startup>
</servlet>

my.package.jerseytest.application.Application

public class Application extends ResourceConfig {
    public Application() {
        ServiceLocator locator = ServiceLocatorUtilities.createAndPopulateServiceLocator();
    }
}

my.package.jerseytest.service.EchoService

@Service
public class EchoService {
    public String generateResponse(String echo) {
        return echo;
    }
}

my.package.jerseytest.resource.MyResource

@Path("myresource")
public class MyResource {

    @Inject
    EchoService echoService;

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String getIt() {
        return echoService.generateResponse("Got it!");
    }
}

Я проверил, что генератор ингибиторов действительно работает и выдает свои результаты, но при запуске сервера Tomcat GETting http://localhost:8080/sandbox/webapi/myresource я получил

SEVERE: Servlet.service() for servlet [Jersey Web Application] in context with path [/sandbox] threw exception [A MultiException has 3 exceptions.  They are:
1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=EchoService,parent=MyResource,qualifiers={},position=-1,optional=false,self=false,unqualified=null,932014249)
2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of my.package.jerseytest.resource.MyResource errors were found
3. java.lang.IllegalStateException: Unable to perform operation: resolve on my.package.jerseytest.resource.MyResource
] with root cause
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=EchoService,parent=MyResource,qualifiers={},position=-1,optional=false,self=false,unqualified=null,932014249)

Есть идеи, что мне не хватает? Буду признателен за любую помощь:(

NB! Я знаю о

но они не помогли мне...

5 ответов

Я объединяю понимание, которое я получил от этих двух вопросов:

Во-первых, используйте генератор метаданных HK2 (или Inhabitant Generator) в своей цепочке сборки (как вы уже сделали). Это отсканирует ваш источник и создаст META-INF/hk2-locator/default,

Во-вторых, создать новый ServiceLocator, заполненный сервисами из метаданных:

ServiceLocator locator = ServiceLocatorUtilities.createAndPopulateServiceLocator();

Теперь передайте это Grizzly, Цитирование Paul Samsotha:

На Джерси есть собственный ServiceLocator, и получить ссылку на него нелегко. Мы могли бы дать Джерси наш ServiceLocator, но в конечном итоге Джерси все еще создает свой собственный локатор и заполнит его нашим локатором.

ResourceConfig config = new MyApplicationConfig();
HttpServer server = GrizzlyHttpServerFactory.createHttpServer(
    URI.create(BASE_URI),
    config, 
    serviceLocator
);

Я решил свою проблему почти так же, как этот, используя класс, который расширяет AbstractBinder, создавая его и регистрируя в приложении.

resourceConfig.register(new DependencyBinder());

Также,

/**
 * dependency injection bindings.
 * Jersey requires that service implementations are bound to their contracts this way.
 */
public final class DependencyBinder extends AbstractBinder {

    @Override
    protected final void configure() {
        bind(StatusServiceImpl.class).to(StatusService.class);
    }
}

Попробуйте добавить @Stateless

@Path("myresource")
@Stateless
public class MyResource {
    @Inject
    EchoService echoService;
...
}

Использование packages(true, "my.package.jerseytest");И использовать org.glassfish.jersey.spi.Contract не org.jvnet.hk2.annotations.Contract аннотаций. И используйте простые интерфейсы без обобщений.

Попробуйте добавить пакеты, которые необходимо отсканировать, в конструкторе приложений. Параметр "true" для пакетов означает рекурсивное сканирование пакета:

public class Application extends ResourceConfig {
    public Application() {
        packages(true, "my.package.jerseytest");
        ServiceLocator locator = ServiceLocatorUtilities.createAndPopulateServiceLocator();
    }
}
Другие вопросы по тегам