|
FrequentlyAskedQuestions
Frequently Asked QuestionsHow do I inject configuration parameters?You need a binding annotation to identify your parameter. Create an annotation class that defines the parameter: /**
* Annotates the URL of the foo server.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER})
@BindingAnnotation
public @interface FooServerAddress {}Bind the annotation to its value in your module: public class FooModule extends AbstractModule {
private final String fooServerAddress;
/**
* @param fooServerAddress the URL of the foo server.
*/
public FooModule(String fooServerAddress) {
this.fooServerAddress = fooServerAddress;
}
@Override public void configure() {
bindConstant().annotatedWith(FooServerAddress.class).to(fooServerAddress);
...
}
}Finally, inject it into your class: public class FooClient {
@Inject
FooClient(@FooServerAddress String fooServerAddress) {
...
}You may save some keystrokes by using Guice's built-in @Named binding annotation rather than creating your own. How do I load configuration properties?Use Names.bindProperties() to create bindings for each of the properties in a configuration file. How do I pass a parameter when creating an object via Guice?You can't directly pass a parameter into an injected value. But you can use Guice to create a Factory, and use that factory to create your object. public class Thing {
// note: no @Inject annotation here
private Thing(A a, B b) {
...
}
public static class Factory {
@Inject
public Factory(A a) { ... }
public Thing make(B b) { ... }
}
}public class Example {
@Inject
public Example(Thing.Factory factory) { ... }
}See AssistedInject, which can be used to remove the factory boilerplate. How do I build two similar but slightly different trees of objects?This is commonly called the "robot legs" problem: How to create a robot with a two Leg objects, the left one injected with a LeftFoot, and the right one with a RightFoot. But only one Leg class that's reused in both contexts. There's a PrivateModules solution. It uses two separate private modules, a @Left one and an @Right one. Each has a binding for the unannotated Foot.class and Leg.class, and exposes a binding for the annotated Leg.class: class LegModule extends PrivateModule {
private final Class<? extends Annotation> annotation;
LegModule(Class<? extends Annotation> annotation) {
this.annotation = annotation;
}
@Override protected void configure() {
bind(Leg.class).annotatedWith(annotation).to(Leg.class);
expose(Leg.class).annotatedWith(annotation);
bindFoot();
}
abstract void bindFoot();
} public static void main(String[] args) {
Injector injector = Guice.createInjector(
new LegModule(Left.class) {
@Override void bindFoot() {
bind(Foot.class).toInstance(new Foot("leftie"));
}
},
new LegModule(Right.class) {
@Override void bindFoot() {
bind(Foot.class).toInstance(new Foot("righty"));
}
});
}See also Alen Vrecko's more complete example. How can I inject an inner class?Guice doesn't support this. However, you can inject a nested class (sometimes called a "static inner class"): class Outer {
static class Nested {
...
}
}How to inject class with generic type?You may need to inject a class with a parameterized type, like List<String>: class Example {
@Inject
void setList(List<String> list) {
...
}
}You can use a TypeLiteral to create the binding. TypeLiteral is a special class that allows you to specify a full parameterized type. @Override public void configure() {
bind(new TypeLiteral<List<String>>() {}).toInstance(new ArrayList<String>());
}Alternately, you can use an @Provides method. @Provides List<String> providesListOfString() {
return new ArrayList<String>();
}How can I inject optional parameters into a constructor?Neither constructors nor @Provides methods support optional injection. To work-around this, you can create an inner class that holds the optional value: class Car {
private final Engine engine;
private final AirConditioner airConditioner;
@Inject
public Car(Engine engine, AirConditionerHolder airConditionerHolder) {
this.engine = engine;
this.airConditioner = airConditionerHolder.value;
}
static class AirConditionerHolder {
@Inject(optional=true) AirConditioner value = new NoOpAirconditioner();
}
}This also allows for a default value for the optional parameter. How do I inject a method interceptor?In order to inject dependencies in an AOP MethodInterceptor, use requestInjection() alongside the standard bindInterceptor() call. public class NotOnWeekendsModule extends AbstractModule {
protected void configure() {
MethodInterceptor interceptor = new WeekendBlocker();
requestInjection(interceptor);
bindInterceptor(any(), annotatedWith(NotOnWeekends.class), interceptor);
}
}Another option is to use Binder.getProvider and pass the dependency in the constructor of the interceptor. public class NotOnWeekendsModule extends AbstractModule {
protected void configure() {
bindInterceptor(any(),
annotatedWith(NotOnWeekends.class),
new WeekendBlocker(getProvider(Calendar.class)));
}
}How can I get other questions answered?Please post to the google-guice discussion group. | |
How can I use @Assisted with Strings (or other distinct parameters of the same type)?
If you use AssistedInject and declare two String parameters, you may have seen an error of the form
To use multiple parameters of the same type, use a named @Assisted annotation with a String value to disambiguate the parameters.
See com.google.inject.assistedinject.FactoryProvider? for documentation and examples.
@Leigh: You need to give the @AssistedAnnotation? a name. Use the same name in both the factory method and in the constructor, and you're golden.
public interface Factory { Person create(@Assisted("givenName") String givenName, @Assisted("surname") String surname); }I don't think the List<String> example works. Every injection of List<String> will be bound to the same ArrayList? (since toInstance() implicitly creates a singleton). This is probably not what the user intended.
Could you connect the dots in How do I inject configuration parameters?, and show how a runtime value for fooServerAddress can actually be set... as that is the point of the whole thing?
In all other examples, the Module and Injector are created in the "client class". I am left to infer that either you are assuming without explanation the existence of another class that fulfills the role of client class in your other examples, or that a static method (perhaps main) does this before instantiating a FooClient. The Injector setup can't be done inside the FooClient? iself, since it depends on Guice injection for its own instantiation.
As the Module constructor takes a fooServerAddress param itself and appears to not be injected, and you have said nothing about nested Injectors, I hope I can assume that the runtime fooServerAddress value would be added by a traditional, procedural new of the Module: new FooModule("runtimeAddr")? If that is so, it looks like Names.bindProperties(Binder, Properties) is the only assistance Guice gives to facilitate scalable and declarative runtime configuration settings... that's pitiful compared to what Spring has had for 7 years.
@blaine.dev: I'm not sure, but perhaps you're confusing the bootstrap class for an application where the Injector is created with the "client class" from the example, which is just a class within the application that depends on the configuration parameter... it's the client that talks to the Foo Server for which the address is injected.
The example assumes you get this fooServerAddress property from somewhere else prior to initializing Guice... the command line or perhaps WebStart?'s BasicService, say. For configuration parameters that you want to read from a file, Names.bindProperties works great.
If there's something specific that you think is lacking, could you explain what that is? Guice makes it pretty easy to extend it to do what you need, generally.
I second blaine.dev. I cant understand how the value is set. Could you please provide an example were you set the value of fooServerAddress from the command line?
Thanks
@ralf.krakowski: What's hard to understand?
public static void main(String[] args) { String fooServerAddress = args[0]; Injector injector = Guice.createInjector(new FooModule(fooServerAddress)); FooClient client = injector.getInstance(FooClient.class); ... }@cgdecker: First, thanks for the code example. Second, no reason to be rude.
Assuming configuration
protected void configure() { bind(new TypeLiteral<Broker<EventType,Date>>(){}).to(new TypeLiteral<SimpleBrokerImpl<Date>>(){}); bind(Main.class); }how can I get instance of parametrized Broker ? The only way I've founded for now is
Broker<EventType, Date> broker = injector.getInstance(Key.get(new TypeLiteral<Broker<EventType, Date>>(){}));Is there any better way?
The (supposed) "commonly called" robot legs problem seems to be a direct result of Guice's main "unit of work" or (perhaps better put) its "fundamental building block" which is, the dependency. Notice the "bind" takes the dependency and then what satisfies it.
The "instance" isn't considered until you ask Guice to 'get(an)Instance'. This makes it great for systems where the object graph is a core set of "Services" (that can be represented by Singletons per class) but for a system based on the orchestration of components, DI frameworks that start with the instance (bean) are much more flexible.
Guice needs an overhaul at the fundamental level to fix this. In Spring this isn't even an issue since you would simply have two beans, both of class Leg, one with an id of "rightLeg," and one with an id of "leftLeg," and they are independently configured with their own dependencies.
I find this really frustrating and I'm hoping someone can tell me I'm wrong here.
Great Robotlegs Example. The dependency injection is functional, but non-native.
Adobe's Flash Platform roadmap is out! Included are ActionScript? 4.0 revelations. From a language design standpoint, Adobe uses the following assumptions as a guide for next-generation ActionScript? development; a) longterm productivity, b) high performance, & c) hardware utilization.
What would Robotlegs developers love to see in AS4? Native dependency injection?
READ ALL THE DETAILS! http://www.rivellomultimediaconsulting.com/actionscript-4-revealed/