Suppose I have a class that looks like this:
public class MyClass {
@Inject
public MyClass(@Foo(\"whatever\") Bar dependency) {
// ...
}
}
>
What you're describing isn't possible through normal Guice: Providers are intended to be zero-argument pure functions and there's no way to plumb the injection site information into them as you would a flexible callback function.
You can approximate what you want, though, two different ways:
If you know every single possible value of @Foo
's parameter, you can make your @Foo
a binding annotation and bind it by providing a Annotation-compatible equals and hashCode. This provides the most intuitive experience: You can do anything with your @Foo
you can do with any other type, such as using @Foo
in constructors or injecting @Foo("value") Provider
.
@Override public void configure() {
for (String value : PREDEFINED_VALUES) {
bind(Bar.class)
.annotatedWith(new FooImpl(value))
.toProvider(new BarProvider(value));
}
}
If you want @Foo
to work for arbitrary parameters, you'll need to extend Guice with custom injections. This won't work for constructor injection or alongside any other @Inject
annotations, but it will allow you to inspect types after Guice injection is finished to augment them as you see fit (e.g. detecting and reacting to @Foo
annotations on fields).
See the example in the Guice docs for more information there.
Internally, Guice's core is effectively a Map
, where a Key represents a pair of a possibly-parameterized type and an optional binding annotation. The former binding annotation trick works because Guice can map your injection request to a Provider all on its own, where the latter skips Guice's map so you can inspect/construct/inject instances all on your own.
If you're willing to skip the annotation part of your solution, you could inject a BarProvider
or BarFactory
that exposes a forFoo(String)
method, which would give you consistent injection without knowing all your String values ahead of time. This would allow you to use assisted injection or AutoFactory to generate your factory (if you want to generate one instance per call), or let you write a straightforward factory yourself for added flexibility.
public class MyClass {
private final Bar dependency;
@Inject
public MyClass(BarProvider barProvider) {
dependency = barProvider.forFoo("whatever");
// ...
}
}