2010-04-05 7 views
25

J'essaye de migrer un petit projet en remplaçant certaines usines par Guice (c'est mon premier essai Guice). Cependant, je suis bloqué en essayant d'injecter des génériques. J'ai réussi à extraire un petit exemple de jouet avec deux classes et un module:Injection de génériques avec Guice

import com.google.inject.Inject; 

public class Console<T> { 
    private final StringOutput<T> out; 
    @Inject 
    public Console(StringOutput<T> out) { 
    this.out = out; 
    } 
    public void print(T t) { 
    System.out.println(out.converter(t)); 
    } 
} 

public class StringOutput<T> { 
    public String converter(T t) { 
    return t.toString(); 
    } 
} 

import com.google.inject.AbstractModule; 
import com.google.inject.Guice; 
import com.google.inject.Injector; 
import com.google.inject.TypeLiteral; 


public class MyModule extends AbstractModule { 

    @Override 
    protected void configure() { 
    bind(StringOutput.class); 
    bind(Console.class); 
    } 

    public static void main(String[] args) { 
    Injector injector = Guice.createInjector(new MyModule()); 
    StringOutput<Integer> out = injector.getInstance(StringOutput.class); 
    System.out.println(out.converter(12)); 
    Console<Double> cons = injector.getInstance(Console.class); 
    cons.print(123.0); 
    } 

} 

Quand je lance cet exemple, tout ce que je suis arrivé est:

Exception dans le thread « principal » com.google.inject.CreationException : Erreurs de création Guice:

1) playground.StringOutput<T> cannot be used as a key; It is not fully specified. 
    at playground.MyModule.configure(MyModule.java:15) 

1 error 
    at com.google.inject.internal.Errors.throwCreationExceptionIfErrorsExist(Errors.java:354) 
    at com.google.inject.InjectorBuilder.initializeStatically(InjectorBuilder.java:152) 
    at com.google.inject.InjectorBuilder.build(InjectorBuilder.java:105) 
    at com.google.inject.Guice.createInjector(Guice.java:92) 

J'ai essayé de rechercher le message d'erreur, mais sans trouver d'indications utiles. Plus loin sur la FAQ de Guice, je tombe sur une question sur la façon d'injecter des génériques. J'ai essayé d'ajouter la liaison suivante dans la méthode configure:

bind(new TypeLiteral<StringOutput<Double>>() {}).toInstance(new StringOutput<Double>()); 

Mais sans succès (même message d'erreur). Est-ce que quelqu'un peut m'expliquer le message d'erreur et me donner quelques conseils? Merci.

Répondre

27

Je pense que le problème spécifique que vous voyez est probablement dû à l'instruction bind(Console.class). Il devrait également utiliser un TypeLiteral. Ou, vous pouvez simplement lier ni l'un ni l'autre et les liaisons JIT s'en occuperont pour vous puisque les deux types impliqués ici sont des classes concrètes.

De plus, vous devez récupérer le Console avec:

Console<Double> cons = 
    injector.getInstance(Key.get(new TypeLiteral<Console<Double>>(){})); 

Edit: Vous n'avez pas besoin de se lier à une instance juste parce que vous utilisez un TypeLiteral. Vous pouvez juste faire:

bind(new TypeLiteral<Console<Double>>(){}); 

Bien sûr, comme je l'ai dit ci-dessus, vous pouvez simplement ignorer que dans ce cas et récupérer le Console de l'injecteur à l'aide d'un Key sur la base TypeLiteral et la liaison serait implicite.

+0

Merci. Je ne suis pas sûr comment lier un TypeLitteral à la console parce que je ne peux pas faire une instance de console sans une instance de StringOutput. Pouvez-vous détailler? – paradigmatic

+0

Voir mon edit ... vous n'avez pas besoin d'utiliser toInstance(). – ColinD

+0

Je viens d'essayer. Cela ne fonctionne que si je définis les caractères littéraux ET que j'utilise la clé pour obtenir l'instance. Donc je ne suis pas capable de rendre la liaison explicite. – paradigmatic