Injecter Générique de la mise en Œuvre à l'aide de Guice
Je voudrais être capable d'injecter un générique de la mise en œuvre d'une interface générique à l'aide de Guice.
public interface Repository<T> {
void save(T item);
T get(int id);
}
public MyRepository<T> implements Repository<T> {
@Override
public void save(T item) {
//do saving
return item;
}
@Override
public T get(int id) {
//get item and return
}
}
En C# à l'aide de Château.Windsor, je serais capable faire:
Component.For(typeof(Repository<>)).ImplementedBy(typeof(MyRepository<>))
mais je ne pense pas que l'équivalent existe dans Guice. Je sais que je peux utiliser TypeLiteral
dans Guice d'enregistrer certaines implémentations, mais est-il possible de s'inscrire tout à la fois comme à Windsor?
Edit:
Voici un exemple d'utilisation:
Injector injector = Guice.createInjector(new MyModule());
Repository<Class1> repo1 = injector.getInstance(new Key<Repository<Class1>>() {});
Repository<Class2> repo2 = injector.getInstance(new Key<Repository<Class2>>() {});
Bien que le plus probable d'utilisation serait injection dans une autre classe:
public class ClassThatUsesRepository {
private Repository<Class1> repository;
@Inject
public ClassThatUsesRepository(Repository<Class1> repository) {
this.repository = repository;
}
}
- Pourriez-vous ajouter un extrait de code montrant comment vous voulez utiliser cette fonction?
- Je suis avec vous, je veux faire la même chose. Tout le monde devrait avoir ce problème. Il doit y avoir quelque chose qu'ils ne nous racontent pas. 🙂
- Je voudrais savoir la solution, je ne sais rien à propos de C#, mais évident que le C# manière est beaucoup plus moderne.
- Toujours pas de solution ? Répéter les liaisons de toutes les valeurs génériques est une perte de temps. Sûr que dans certains cas, vous pourriez réellement envie d'une mise en œuvre différente, mais il ne devrait pas être la valeur par défaut.
Vous devez vous connecter pour publier un commentaire.
Pour l'utilisation des génériques avec Guice, vous devez utiliser le TypeLiteral classe de lier le générique de variantes. Ceci est un exemple de la façon dont vous êtes Guice injecteur de configuration pourrait ressembler à:
(Référentiel est l'interface générique, MyRepository est le générique de la mise en œuvre, Class1 est la classe utilisée dans le générique).
Génériques de ne pas être retenu au moment de l'exécution sûr, il est plus difficile de saisir le concept au premier abord.
De toute façon, il y a des raisons
new ArrayList<String>().getClass()
retourneClass<?>
et pasClass<String>
et bien sûr de le jeter auxClass<? extends String>
vous devriez vous rappeler que les génériques sont là juste pour le type de compilation des contrôles (un peu comme implicite de validation, si vous voulez).Donc, si vous voulez utiliser Guice à injecter
MyRepository
(avec n'importe quel type) de la mise en œuvre chaque fois que vous avez besoin d'une nouvelle instance deRepository
(avec n'importe quel type), alors vous n'avez pas à réfléchir sur les génériques à tous, mais vous êtes sur votre propre pour assurer la sécurité de type (c'est pourquoi vous obtenez ces satanés "unchecked" avertissement).Voici un exemple de code fonctionne très bien:
Cette affiche:
Mais cette liste est mis en œuvre par un
LinkedList
. Bien que dans cet exemple, si vous avez essayé d'assigner un int quelque chose qui est Chaîne vous obtenez une exception.Mais si vous voulez obtenir un produit injectable objet déjà de type "castés" et dandy, vous pouvez demander de
List<String>
au lieu de simplement la Liste, mais alors Guice permettra de traiter ce Type de variable dans le cadre de la liaison de clé (similaire à un qualificatif comme @Nommé). Ce que cela signifie est que si vous voulez injection spécifiquementList<String>
deArrayList<String>
la mise en œuvre etList<Integer>
deLinkedList<Integer>
, Guice vous permet de le faire (pas testé, supposition).Mais il y a un hic:
Comme vous pouvez le remarquer classe littéraux ne sont pas génériques. C'est là que vous utilisez Guice est
TypeLiterals
.TypeLiterals
conserver le type générique de la variable dans le cadre de la méta-information à la carte à la mise en œuvre. Espérons que cette aide.Vous pouvez utilisation (abusive?) le
@ImplementedBy
annotation de faire Guice générer générique liaisons pour vous:Tant que juste-à-temps, les liaisons sont activées, vous pouvez injecter
Repository<Whatever>
sans aucune liaison explicite:Le hic, c'est que la cible de la liaison est
MyRepository
, plutôt que deMyRepository<T>
:Ce n'est généralement pas un problème, mais cela signifie que
MyRepository
ne pouvez pas injecter unTypeLiteral<T>
à la figure de son propre type à l'exécution, ce qui serait particulièrement utile dans cette situation. A côté de cela, au meilleur de ma connaissance, cela fonctionne bien.(Si quelqu'un se sent comme la fixation de ce, je suis sûr qu'on aurait juste besoin de quelques calculs supplémentaires ici de remplir le type de cible les paramètres de la source de la clé.)
Liée en quelque sorte, j'espère que quelqu'un va trouver cela utile. Dans certains cas, surtout si vous avez de la java.lang.Class instance du type que vous voulez faire de généralité, il est possible de forcer une injection dans l'exécution, par l'extension de la ParameterizedType classe.
Dans la solution ci-dessous, une méthode de fabrique, crée un générique Collection< ? s'étend Nombre> et Map < K,V > donnée une instance de la classe de l'objet
Example.java:
CompositeType.java: