2009-07-11 7 views
3

J'ai quelques types qui ressemblent à ceReconstruire types génériques à l'exécution avec Guice via les types et TypeLiterals

// a value that is aware of its key type (K) 
Bar<K> 
// something that deals with such values and keys 
Foo<V extends Bar<K>, K> 

Comment peut-on recréer Foo tel que vous pouvez le consommer dans Guice? Le bit sur lequel je suis coincé est comment faire une référence croisée du K de Bar au 2ème type paramétré de Foo.

Ainsi, par exemple,

WildcardType kType = Types.subtypeOf(Object.class); 
WildcardType barType = 
    Types.subtypeOf(Types.newParameterizedType(Bar.class, pipeKey)); 
ParameterizedType fooType = 
    Types.newParameterizedType(Foo.class, pipelineableType, pipeKey); 

vraiment cela semble mal car il est essentiellement:

Foo<V extends Bar<? extends Object>, ? extends Object> 

Ce qui n'est pas la même chose que:

Foo<V extends Bar<K>, K> 

Comme dans ce dernier cas I sais que K est un type cohérent.

Des idées?

Vive

Matt

Répondre

4

De la JavaDoc pour Binder:

Guice ne peut pas se lier actuellement ou injecter un type générique, comme Set<E> tous les paramètres de type doivent être entièrement spécifiées .

Vous pouvez créer des liaisons pour Foo quand K et V sont liés. Si vous devez créer des liaisons pour Foo pour plusieurs types de clés, vous pouvez créer une méthode facilitant ces liaisons. Une façon de le faire est de créer une méthode comme celui-ci dans votre module:

<K, V extends Bar<K>> AnnotatedBindingBuilder<Foo<V, K>> bind(Class<K> keyType, 
    Class<V> barType) { 
    ParameterizedType bType = Types.newParameterizedType(Bar.class, keyType); 
    ParameterizedType fType = Types.newParameterizedType(Foo.class, barType, 
     keyType); 

    @SuppressWarnings("unchecked") 
    TypeLiteral<Foo<V, K>> typeLiteral = 
     (TypeLiteral<Foo<V, K>>) TypeLiteral.get(fType); 

    return bind(typeLiteral); 
} 

Ensuite, si vous avez ces classes:

class StringValue implements Bar<String> { 
    ... 
} 

class StringValueProcessor implements Foo<StringValue, String> { 
    ... 
} 

Vous pouvez créer une reliure comme ceci:

bind(String.class, StringValue.class).to(StringValueProcessor.class); 

... pour que Guice puisse injecter dans une classe comme celle-ci:

static class Target { 
    private final Foo<StringValue, String> foo; 

    @Inject 
    public Target(Foo<StringValue, String> foo) { 
    this.foo = foo; 
    } 
} 
+0

intéressant, je n'avais pas pensé à une liaison de cette façon. Ce que je cherche vraiment la capacité de rechercher un ensemble de liaisons qui correspondent à une spécification qui peut inclure certains paramètres de type, par exemple.toutes les liaisons qui sont Foo , String> si je suppose que dans ce cas, il suffit de simplement chercher Foo ... hmmm – Matt

+0

Avez-vous vu http://stackoverflow.com/questions/1100784/guice-spi-find-bindings -by-wildcard-types? – NamshubWriter

+0

oui c'est mon Q aussi bien, j'ai implémenté cela d'une manière qui fonctionne jusqu'ici ... mais je me demandais comment l'étendre à un cas plus général. A la réflexion je ne suis pas sûr que ce soit même nécessaire car c'est juste un joker. Je dois y réfléchir un peu plus ... – Matt

0

usine de Guice ne peut pas construire TypeVariable instances. Vous devrez implémenter cette interface directement comme vous en avez besoin.

Notez que Guice n'autorise pas les liaisons pour les types qui ne sont pas entièrement qualifiés. Par exemple, vous pouvez lier un Map<String, Integer> mais vous ne pouvez pas lier un Map<K, V>.