Ошибка проверки модели ресурса в приложении JerseyTest для приложения Spring-Jersey

У меня есть аннотированное приложение Spring-Jersey. Я пытаюсь настроить модульный тест для моих контроллеров, используя JerseyTest, Я получаю следующие ошибки при запуске теста, которые я не могу выяснить. Что я пропустил?

SEVERE: Following issues have been detected: 
WARNING: No injection source found for a parameter of type public com.example.services.dto.UnitDto com.example.apis.UnitResource.getUnits(com.example.services.dto.PointDto) throws com.example.exceptions.PointOutsideBounds at index 2.

Validation of the application resource model has failed during application initialization.
[[FATAL] No injection source found for a parameter of type public com.example.services.dto.UnitDto com.example.apis.UnitResource.getUnits(com.example.services.dto.PointDto) throws com.example.exceptions.PointOutsideBounds at index 2.; source='ResourceMethod{httpMethod=GET, consumedTypes=[], producedTypes=[application/json], suspended=false, suspendTimeout=0, suspendTimeoutUnit=MILLISECONDS, invocable=Invocable{handler=ClassBasedMethodHandler{handlerClass=class com.example.apis.UnitResource, handlerConstructors=[org.glassfish.jersey.server.model.HandlerConstructor@31a5870e]}, definitionMethod=public com.example.services.dto.UnitDto com.example.apis.UnitResource.getUnits(com.example.services.dto.PointDto) throws com.example.exceptions.PointOutsideBounds, parameters=[Parameter [type=class com.example.services.dto.PointDto, source=contains, defaultValue=null]], responseType=class com.example.services.dto.UnitDto}, nameBindings=[]}']
    at org.glassfish.jersey.server.ApplicationHandler.initialize(ApplicationHandler.java:555)

Класс контроллера выглядит следующим образом:

@Component
@Path("/app/units")
public class UnitResource {
    @Context
    private UriInfo uriInfo;
    @Context
    private Request request;

    @Inject
    private UnitService unitService;

    @Inject
    public UnitResource(@Named("UnitService") UnitService unitService) {
        this.unitService = unitService;
    }

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Timed(absolute = true, name = "getUnitForPoint")
    public UnitDto getUnits(@QueryParam("contains") @NotNull PointDto point) throws PointOutsideBounds {
        return unitService.getUnitForPoint(point);
    }
}

Тестовый класс выглядит следующим образом:

public class UnitResourceTest extends JerseyTest {

    @Mock
    private UnitService unitService;

    @Override
    protected ResourceConfig configure() {
        ResourceConfig rc = new ResourceConfig()
        //      .register(new UnitResource(Mockito.mock(UnitService.class))) -- has the same effect
                .register(UnitResource.class)
                .property("contextConfig", new AnnotationConfigApplicationContext(ApplicationConfiguration.class));

        enable(TestProperties.LOG_TRAFFIC);
        enable(TestProperties.DUMP_ENTITY);
        forceSet(TestProperties.CONTAINER_PORT, "0");

        return rc;
    }

    @Before
    public void setUp() throws Exception {
        super.setUp();
        initMocks(this);
    }

    @Override
    protected TestContainerFactory getTestContainerFactory() {
        return new InMemoryTestContainerFactory();
    }

    @Test
    public void testGetUnit() throws PointOutsideBounds {

        Response response = target()
                .path("/app/units")
                .queryParam("contains", new Point(0.0,0.0).toJson())
                .request(MediaType.APPLICATION_JSON_TYPE)
                .get();

        assertThat(response.getStatus(), is(Response.Status.OK));
    }
}

Класс конфигурации приложения:

@Configuration
@ComponentScan("com.example")
public class ApplicationConfiguration {
    @Bean(name="UnitService")
    public UnitService unitService() {
        return new UnitService();
    }
}

Мои зависимости Gradle для тестовой конфигурации:

dependencies {
    // Using junit-dep package to get junit without hamcrest dependency
    testCompile("junit:junit-dep:4.8.2")
    testCompile("org.hamcrest:hamcrest-all:1.3")
    testCompile("org.mockito:mockito-all:1.8.4")
    testCompile ('org.glassfish.jersey.test-framework:jersey-test-framework-core:2.22.2')
    testCompile('org.glassfish.jersey.test-framework.providers:jersey-test-framework-provider-inmemory:2.22.2')
}

configurations {
    testCompile.exclude group: 'org.glassfish.jersey.ext', module: 'jersey-spring3'
}

Я нашел это и это, но ни один не решил мою проблему.

1 ответ

Решение

Примечание. По большей части этот ответ относится ко всем @XxxParam аннотированные параметры.

PointDto Параметр кажется проблемой

public UnitDto getUnits(@QueryParam("contains") @NotNull PointDto point)

Параметры запроса - это строки. Джерси имеет возможность конвертировать эту строку в некоторые основные типы, такие как int, boolean, Date и т. д. Но он понятия не имеет, как создать PointDto из этой строки. Это не значит, что мы не можем использовать пользовательские типы. Нам просто нужно следовать некоторым правилам:

  1. Есть конструктор, который принимает строку. Затем нам нужно самим построить объект из этой строки. Например

    public PointDto(String param) {
        Map<String, Object> map = parseJson(param);
        this.field1 = map.get("field1");
        this.field2 = map.get("field2");
    }
    

    Это немного работы.

  2. Другой вариант - иметь статический fromString(String) или статический valueOf(String) в классе. Джерси вызовет этот метод для создания объекта. Так, например, вы можете иметь в своем PointDto учебный класс

    public static PointDto fromString(String param) {
        PointDto dto = parseJson(param);
        return dto;
    }
    
  3. Вы можете иметь ParamConverterProvider, Я не буду приводить пример, но вы можете прочитать больше в этой хорошей статье о том, как вы можете реализовать его. Вы также можете увидеть этот пост

Обратите внимание, информация, представленная в этом ответе, находится в javadoc для @QueryParam,

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