Как смоделировать введенное значение, опираясь на классификатор, используя JerseyTest - PullRequest
0 голосов
/ 07 мая 2019

Я пытаюсь смоделировать контроллер / ресурс, включая слой jax-rs. У класса есть зависимости, которые нужно внедрить. Однако он также имеет некоторые значения String, которые вводятся с использованием интерфейса квалификатора.

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

Это нормально работает для обычных внедренных зависимостей, но при добавлении дополнительной аннотации @SomeQualifierInterface происходит сбой со следующей ошибкой:

MultiException stack 1 of 3
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=String,parent=ThingsController,qualifiers={@com.company.SomeQualifierInterface()},position=-1,optional=false,self=false,unqualified=null,10035302)
  ...
MultiException stack 2 of 3
java.lang.IllegalArgumentException: While attempting to resolve the dependencies of com.company.ThingsController errors were found
  ...
MultiException stack 3 of 3
java.lang.IllegalStateException: Unable to perform operation: resolve on com.company.ThingsController
  ...

См. Упрощенный пример полного кода ниже:

Контроллер / Ресурс

import org.slf4j.Logger;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;

@Path("/things")
public class ThingsController {

  @Inject
  private Logger log;

  @Inject
  @SomeQualifierInterface
  private String injectedQualifierValue;

  @GET
  public Response getThings() {
    log.info("getting things");
    System.out.println("Injected value: " + injectedQualifierValue);
    return Response.status(200).entity("hello world!").build();
  }
}

Интерфейс классификатора

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.inject.Qualifier;

@Qualifier
@Retention(RUNTIME)
@Target({ TYPE, METHOD, FIELD, PARAMETER })
public @interface SomeQualifierInterface { }

Предоставление услуг

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.Dependent;
import javax.enterprise.inject.Produces;

@ApplicationScoped
public class SomeProducerService {

  @Produces
  @Dependent
  @SomeQualifierInterface
  public String getQualifierValue() {
    return "some value!";
  }
}

Test

import org.glassfish.jersey.internal.inject.AbstractBinder;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
import org.slf4j.Logger;

import javax.ws.rs.core.Application;
import javax.ws.rs.core.Response;

import static junit.framework.TestCase.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;


public class MockedThingsControllerTest extends JerseyTest {

  private Logger logMock = mock(Logger.class);

  @Override
  protected Application configure() {
    ResourceConfig resourceConfig = new ResourceConfig(ThingsController.class);
    resourceConfig.register(new AbstractBinder() {
      @Override
      protected void configure() {
        bind(logMock).to(Logger.class);

        bind("some mocked value").to(String.class); // Doesn't work
        bind(new SomeProducerService()).to(SomeProducerService.class); // Doesn't work
      }
    });
    return resourceConfig;
  }

  @Test
  public void doSomething() {
    Response response = target("/things").request().get();
    assertEquals(200, response.getStatus());
    verify(logMock).info("getting things");
  }
}

POM

<dependency>
  <groupId>org.mockito</groupId>
  <artifactId>mockito-core</artifactId>
  <version>2.27.0</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>org.glassfish.jersey.test-framework</groupId>
  <artifactId>jersey-test-framework-core</artifactId>
  <version>2.28</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>org.glassfish.jersey.test-framework.providers</groupId>
  <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
  <version>2.28</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>org.glassfish.jersey.inject</groupId>
  <artifactId>jersey-hk2</artifactId>
  <version>2.28</version>
  <scope>test</scope>
</dependency>

1 Ответ

1 голос
/ 10 мая 2019

Решено!

Во-первых, используйте AbstractBinder из org.glassfish.hk2.utilities.binding.AbstractBinder вместо org.glassfish.jersey.internal.inject.AbstractBinder.

Во-вторых, создайте класс, расширяющий AnnotationLiteral и реализующий интерфейс.

Наконец, свяжите значение с TypeLiteral и установите для qualBy значение AnnotationLiteral.

Полный код:

import org.glassfish.hk2.api.AnnotationLiteral;
import org.glassfish.hk2.api.TypeLiteral;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
import org.slf4j.Logger;

import javax.ws.rs.core.Application;
import javax.ws.rs.core.Response;

import static junit.framework.TestCase.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;


public class MockedThingsControllerTest extends JerseyTest {

  private Logger logMock = mock(Logger.class);

  @Override
  protected Application configure() {
    ResourceConfig resourceConfig = new ResourceConfig(ThingsController.class);
    resourceConfig.register(new AbstractBinder() {
      @Override
      protected void configure() {
        bind(logMock).to(Logger.class);
        bind("some mocked value").to(new TypeLiteral<String>() {}).qualifiedBy(new SomeQualifierLiteral());
      }
    });
    return resourceConfig;
  }

  @Test
  public void doSomething() {
    Response response = target("/things").request().get();
    assertEquals(200, response.getStatus());
    verify(logMock).info("getting things");
  }

  static class SomeQualifierLiteral extends AnnotationLiteral<SomeQualifierInterface> implements SomeQualifierInterface {}
}
...