Rekonstruieren generische Typen zur Laufzeit mit Guice über Typen und TypeLiterals
-
12-09-2019 - |
Frage
Ich habe ein paar Typen, die wie diese sind
// 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>
Wie würde man neu Foo, so dass Sie es in Guice verbrauchen könnte? Das Bit ich bin fest ist, wie in die 2. parametrisierte Art von Foo Referenz die K von Bar zu überqueren.
So zum Beispiel,
WildcardType kType = Types.subtypeOf(Object.class);
WildcardType barType =
Types.subtypeOf(Types.newParameterizedType(Bar.class, pipeKey));
ParameterizedType fooType =
Types.newParameterizedType(Foo.class, pipelineableType, pipeKey);
Wirklich scheint falsch, wie es ist im Grunde:
Foo<V extends Bar<? extends Object>, ? extends Object>
Was ist nicht das Gleiche wie:
Foo<V extends Bar<K>, K>
Wie im letzteren Fall I weiß , dass K eine konsistente Art ist.
Irgendwelche Ideen?
Prost
Matt
Lösung
Von der JavaDoc für Binder :
Guice können derzeit nicht binden oder injizieren alle ein generischer Typ, wie
Set<E>
Typ Parameter müssen vollständig sein angegeben.
Sie können Bindungen für Foo
erstellen, wenn K
und V
gebunden sind.
Wenn Sie Bindungen für Foo
für mehr als eine Art von Schlüssel vornehmen müssen, können Sie eine Methode machen, die es einfacher zu machen, diese Bindungen machen. Eine Möglichkeit, das zu tun, ist eine Methode, wie Sie dies in Ihrem Modul zu erstellen:
<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);
}
Dann, wenn Sie diese Klassen haben:
class StringValue implements Bar<String> {
...
}
class StringValueProcessor implements Foo<StringValue, String> {
...
}
Sie können eine Bindung wie folgt erstellen:
bind(String.class, StringValue.class).to(StringValueProcessor.class);
... so dass Guice in eine Klasse wie folgt injizieren könnte:
static class Target {
private final Foo<StringValue, String> foo;
@Inject
public Target(Foo<StringValue, String> foo) {
this.foo = foo;
}
}
Andere Tipps
Guice Fabrik kann TypeVariable
Instanzen nicht bauen. Sie müssen diese Schnittstelle direkt implementieren, wie Sie es brauchen.
Beachten Sie, dass Guice nicht Bindungen für Typen erlauben, die nicht voll qualifiziert sind. Zum Beispiel können Sie ein Map<String, Integer>
binden, aber Sie eine Map<K, V>
nicht binden können.