2015-06-12 3 views
3

У меня есть следующие реализации для (2.18) приложений Джерси:Нет объектов для ошибок впрыска при использовании bindFactory

public class RootApplication extends ResourceConfig { 

    public RootApplication() { 
     packages("com.foo.bar"); 

     register(new AbstractBinder() { 

      @Override 
      protected void configure() {  
       bindFactory(RepositoryFactory.class).to(Repository.class); 

       // if I use following line instead of bindFactory it works 
       // bind(OracleRepository.class).to(Repository.class); 
      } 
     }); 
    } 

    public class RepositoryFactory implements Factory<Repository> { 

     private final Repository repo; 

     public RepositoryFactory() { 
      this.repo = new OracleRepository(); 
     } 

     @Override 
     public Repository provide() { 
      return repo; 
     } 

     @Override 
     public void dispose(Repository repo) { 
     } 
    } 
} 

и получить исключение ниже при попадании в службе, которая впрыскивает Repository

javax.servlet.ServletException: A MultiException has 3 exceptions. They are: 
1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=Repository,parent=MeasureService,qualifiers={},position=-1,optional=false,self=false,unqualified=null,56464420) 
2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of com.fidelity.pi.dashboard.rest.MeasureService errors were found 
3. java.lang.IllegalStateException: Unable to perform operation: resolve on com.fidelity.pi.dashboard.rest.MeasureService 

Все работает, если я прокомментирую bindFactory и воспользуюсь комментируемым связыванием. Я что-то пропускаю с точки зрения реализации Factory? Исключение, похоже, произойдет еще до того, как будет удален конструктор RepositoryFactory. Мне нужна фабрика, так как у меня есть другая инициализация, которую нужно сделать на примере OracleRepository.

ответ

2

Единственный способ, которым я смог воспроизвести проблему (с вашей неполной информацией, т. Е. Отсутствующей точкой впрыска), было попытаться ввести OracleRepository вместо Repository. У меня нет точной причины, почему инъекция терпит неудачу, но я думаю, это потому, что вы связываете Repository, а не OracleRepository. Если это проблема, самым простым решением было бы привязать завод к OracleRepository или вместо этого просто ввести Repository.

Для инъекции Repository, если вы хотите, чтобы квалифицировать различные варианты реализации вы можете сделать так, приковав named или qaulifiedBy для связывания, как в примере ниже (где я named и аннотировать точку впрыска с @Named).

В примере я использовал Jersey Test Framework

<dependency> 
    <groupId>org.glassfish.jersey.test-framework.providers</groupId> 
    <artifactId>jersey-test-framework-provider-inmemory</artifactId> 
    <version>${jersey2.version}</version> 
    <scope>test</scope> 
</dependency> 

Вот полный тест. Вы можете изменить @Named между "Sql" и "Oracle", чтобы увидеть разницу.

import javax.inject.Inject; 
import javax.inject.Named; 
import javax.ws.rs.GET; 
import javax.ws.rs.Path; 
import javax.ws.rs.core.Application; 
import javax.ws.rs.core.Response; 
import org.glassfish.hk2.api.Factory; 
import org.glassfish.hk2.utilities.binding.AbstractBinder; 
import org.glassfish.jersey.server.ResourceConfig; 
import org.glassfish.jersey.test.JerseyTest; 
import org.junit.Assert; 
import org.junit.Test; 

public class InjectionTest extends JerseyTest { 

    @Path("test") 
    public static class SimpleResource { 

     @Inject 
     @Named("Oracle") 
     private Repository repo; 

     @GET 
     public String getRepoName() { 
      return repo.getClass().getSimpleName(); 
     } 
    } 

    @Override 
    public Application configure() { 
     ResourceConfig config = new ResourceConfig(); 
     config.register(SimpleResource.class); 
     config.register(new AbstractBinder(){ 
      @Override 
      protected void configure() { 
       bindFactory(SqlFactory.class) 
         .to(Repository.class).named("Sql"); 
       bindFactory(OracleFactory.class) 
         .to(Repository.class).named("Oracle"); 
      } 
     }); 
     return config;  
    } 


    public static interface Repository {} 

    public static class OracleRepository implements Repository {} 

    public static class SqlRepository implements Repository {} 

    public static class SqlFactory implements Factory<Repository> { 

     @Override 
     public Repository provide() { 
      return new SqlRepository(); 
     } 

     @Override 
     public void dispose(Repository t) {} 
    } 

    public static class OracleFactory implements Factory<Repository> { 

     @Override 
     public Repository provide() { 
      return new OracleRepository(); 
     } 

     @Override 
     public void dispose(Repository t) {} 
    } 

    /** 
    * Change the `Assert` from "OracleRepository" to "SqlRepository" 
    * when switching the `@Named` on the injection point. 
    */ 
    @Test 
    public void testInjectOk() { 
     Response response = target("test").request().get(); 
     String respString = response.readEntity(String.class); 
     Assert.assertEquals("OracleRepository", respString); 
     System.out.println(respString); 
    } 
} 

Если у вас есть проблемы, пожалуйста, напишите полный один тестовый класс случай, как я выше, что демонстрирует проблему.

+1

Спасибо за рабочий образец .. после немного назад и вперед я обнаружил причину ошибки, хотя я не совсем понял почему. Обратите внимание, что мой класс Factory не был статичным, и это, похоже, проблема. Аналогично это произойдет с образцом, который у вас выше, как только Factory не статичен. –

+0

Ahhh. Я полностью не понял этого из вашего кода. Я думал, что это два разных файла. Да для внутренних классов они должны быть статическими. Я думаю, что класс не может быть создан с помощью фреймворка, если это не так. См. [Здесь] (http://stackoverflow.com/q/12690128/2587435) для некоторых интересных чтений по этому вопросу –

Смежные вопросы