2017-01-14 3 views
2

Я пытаюсь ввести класс Generic типа (скажем, ClassA) в другой класс (скажем, ClassB) с помощью Guice с аннотацией @Inject. Код класса, который впрыскивают показан ниже:Ошибка ввода класса с общим типом @Inject Guice

public interface InterfaceA<T> { 

} 

public class ClassA<T> implements InterfaceA<T> { 
    private final Class<T> data; 
    private Dependency1 dependency1; 

    @Inject 
    public ClassA(Class<T> data, Dependency1 dependency1) { 
     this.data = data; 
     this.dependency1 = dependency1; 
    } 

} 

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

public class ClassB { 
    private InterfaceA<Entity1> interfaceA; 

    @Inject 
    public ClassB(InterfaceA<Entity1> interfaceA) { 
     this.interfaceA = interfaceA; 
    } 
} 

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

public class MyModule extends AbstractModule { 
    @Override 
    protected void configure() { 
     bind(new TypeLiteral<InterfaceA<Entity1>>(){}).to(new TypeLiteral<InterfaceA<Entity1>>(){}); 
    } 
} 

Однако, при запуске приложения возникает следующая ошибка:

ERROR [2017-01-14 19:54:00,646] com.hubspot.dropwizard.guice.GuiceBundle: Exception occurred when creating Guice Injector - exiting 
! com.google.inject.CreationException: Unable to create injector, see the following errors: 
! 
! 1) Could not find a suitable constructor in java.lang.Class. Classes must have either one (and only one) constructor annotated with @Inject or a zero-argument constructor that is not private. 
! at java.lang.Class.class(Class.java:119) 

Любые входные данные о том, как решить эту проблему, будут действительно полезны. Заранее спасибо.

+0

Почему вы пытаетесь ввести «класс » во что-то? Разве не все дело в том, что вы будете знать тип в модуле? – durron597

+0

Я хочу ввести его, потому что я хочу знать тип вводимого класса во время выполнения. – user3375226

+0

Это похоже на то, что программирование OO. Также все классы имеют метод '.getClass', чего недостаточно? – durron597

ответ

2

Вы не можете сделать это декларативным способом. Вы должны использовать методы поставщика:

public class MyModule extends AbstractModule { 
    @Override protected void configure() {} 

    @Provides InterfaceA<Entity1> provideInterfaceAEntity1(Dependency1 dep) { 
    return new ClassA<Entity1>(Entity1.class, dep); 
    } 
} 

Это единственный путь, потому что вы не можете автоматически вводить Class<T> в ClassA.

Вам нужен такой метод в вашем Module для каждого Entity, который вы хотите связать с InterfaceA.

+0

Спасибо за ваше решение! Однако в этом случае мы перемещаем все зависимости ClassA за пределами этого класса, что, по-видимому, не является чистым способом. Кроме того, мы не используем функцию @Inject Guice здесь, но создаем новый объект, используя new(). Я нашел другой способ сделать это. Проверьте мое решение. – user3375226

+0

@ user3375226 Использование 'new' не запрещено с помощью Guice. Использование '@ Inject' даже не является обязательным. Более того, Guice рекомендует, чтобы конструктор запрашивал конечный объект. С 'literal.getRawType()' вы нарушаете эту рекомендацию. Я считаю, что это решение - самый лучший Guice-y. –

1

Я наконец нашел решение. Здесь вместо того, чтобы вводить Class<T> data в конструкторе ClassA, я вводил TypeLiteral<T> literal и читал тип класса из TypeLiteral, используя метод getRawType().

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

public class ClassA<T> implements InterfaceA<T> { 
    private final Class<? super T> data; 
    private Dependency1 dependency1; 

    @Inject 
    public ClassA(TypeLiteral<T> literal, Dependency1 dependency1) { 
     this.data = literal.getRawType(); 
     this.dependency1 = dependency1; 
    } 
} 

Остальная часть кода для других классов остается такой же, как и раньше.

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