Resteasy и Google Guice: как использовать несколько @ApplicationPath и ресурс с @Injection?

Я создал проект для проверки внедрения зависимостей, предлагаемого Google Guice на моих ресурсах Jax-rs, с помощью Resteasy.

Мои намерения таковы:

  • Используйте несколько @ApplicationPath для версий моего API. В каждом классе отмечены @ApplicationPath Я загружаю набор классов для конкретной версии.
  • Каждый ресурс имеет @Inject (из Google Guice) в своем конструкторе для внедрения некоторых сервисов.

Я создал два класса с пометкой @ApplicationPath: ApplicationV1RS а также ApplicationV2RS, В оба я добавил одинаковые ресурсы классов (UserResource а также HelloResource), только для моего теста.

Мой модуль настроен так:

public class HelloModule implements Module
{
   public void configure(final Binder binder)
   {
      binder.bind(IGreeterService.class).to(GreeterService.class);

      binder.bind(IUserService.class).to(UserService.class);
   }
}

Когда я звоню http://localhost:9095/v1/hello/world или же http://localhost:9095/v2/hello/worldЯ получаю ту же ошибку:

java.lang.RuntimeException: RESTEASY003190: Could not find constructor 
    for class: org.jboss.resteasy.examples.guice.hello.HelloResource

Ну, как я и ожидал, это не работает. Google Guice не является "умным" для создания экземпляров классов ресурсов, используя для меня конструктор.

Но я не могу найти способ работать. Честно говоря, я не совсем понимаю, как Google Guice, Jetty и Resteasy играют друг с другом в этом сценарии.

Если я откажусь от идеи использования @ApplicationPathмои ресурсы работают с Google Guice HelloModule как это:

public class HelloModule implements Module
{
   public void configure(final Binder binder)
   {
      binder.bind(HelloResource.class);
      binder.bind(IGreeterService.class).to(GreeterService.class);

      binder.bind(UserResource.class);
      binder.bind(IUserService.class).to(UserService.class);
   }
}

Но в этом случае я передаю управление для регистрации своих ресурсов (HelloResource а также UserResource) Guice. Это не гибко для меня, я не могу настроить несколько @ApplicationPath,

Итак, что я упускаю или не понимаю?

Я создал проект с проблемным кодом. Очень прост в настройке и тестировании: https://github.com/dherik/resteasy-guice-hello/tree/so-question/README.md

Спасибо!

1 ответ

Решение

Когда у тебя есть getClasses Затем в вашем Приложении он пытается создать экземпляр для всех зарегистрированных ресурсов, используя конструктор по умолчанию, отсутствующий в нашем классе Resources. Один из способов - создать конструктор по умолчанию и внедрить зависимости через метод установки Injection. И тогда вместо переопределения getClasses в ApplicationV1RS а также ApplicationV2RS ты переопределяешь getSingletons, Так как ресурсы могут быть синглтон.

Ниже приведены изменения, которые я сделал, чтобы все заработало так, как вы хотите.

ApplicationV1RS.java

@ApplicationPath("v1")
public class ApplicationV1RS extends Application {

    private Set<Object> singletons = new HashSet<Object>();

    public ApplicationV1RS(@Context ServletContext servletContext) {
    }

    @Override
    public Set<Object> getSingletons() {
        Injector injector = Guice.createInjector(new HelloModule());

        HelloResource helloResource = injector.getInstance(HelloResource.class);
        UserResource userResource = injector.getInstance(UserResource.class);
        singletons.add(helloResource);
        singletons.add(userResource);
        return singletons;
    }
}

ApplicationV2RS.java

@ApplicationPath("v2")
public class ApplicationV2RS extends Application {

    private Set<Object> singletons = new HashSet<Object>();

    public ApplicationV2RS(@Context ServletContext servletContext) {
    }

    @Override
    public Set<Object> getSingletons() {
        Injector injector = Guice.createInjector(new HelloModule());

        HelloResource helloResource = injector.getInstance(HelloResource.class);
        UserResource userResource = injector.getInstance(UserResource.class);
        singletons.add(helloResource);
        singletons.add(userResource);
        return singletons;
    }
}

HelloResource.java

@Path("hello")
public class HelloResource {
    @Inject
    private IGreeterService greeter;

    public HelloResource() {
    }

    @GET
    @Path("{name}")
    public String hello(@PathParam("name") final String name) {
        return greeter.greet(name);
    }
}

UserResource.java

@Path("user")
public class UserResource {

    @Inject
    private IUserService userService;

    public UserResource() {
    }

    @GET
    @Path("{name}")
    public String hello(@PathParam("name") final String name) {
        return userService.getUser(name);
    }
}

добавлять @Singleton к вашим классам обслуживания.

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

Я также выдвинул код для разветвленного репо. проверить это

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