Guice: One "Provider<T>" for multiple implementations - java

I have an interface that has 20 or so annotated implementations. I can inject the correct one if I know which I need at compile time, but I now need to dynamically inject one based on runtime parameters.
As I understood the documentation, I would have to use 20 or so Provider<T> injections and then use the one I need, which seems rather excessive to me. Is there a way to have something like an inst(Provider<T>).get(MyAnnotation.class) to bind a specific implementation, and then have only that Provider injected into my class?

Inject a MapBinder.
In your module, load the bindings into the MapBinder, then make your runtime parameters injectable as well. This example is based on the one in the documentation:
public class SnacksModule extends AbstractModule {
protected void configure() {
MapBinder<String, Snack> mapbinder
= MapBinder.newMapBinder(binder(), String.class, Snack.class);
mapbinder.addBinding("twix").to(Twix.class);
mapbinder.addBinding("snickers").to(Snickers.class);
mapbinder.addBinding("skittles").to(Skittles.class);
}
}
Then, in your object, inject the Map and the parameter. For this example I will assume you've bound a java.util.Properties for your runtime parameters:
#Inject
public MyObject(Map<String, Provider<Snack>> snackProviderMap, Properties properties) {
String snackType = (String) properties.get("snackType");
Provider<Snack> = snackProviderMap.get(property);
// etc.
}
Note, with the same MapBinder you can inject either a simple Map<String, Snack> or a Map<String, Provider<Snack>>; Guice binds both.

If all you want is to get an instance programmatically, you can inject an Injector. It's rarely a good idea--injecting a Provider<T> is a much better idea where you can, especially for the sake of testing--but to get a binding reflectively it's the only way to go.
class YourClass {
final YourDep yourDep; // this is the dep to get at runtime
#Inject YourClass(Injector injector) {
YourAnnotation annotation = deriveYourAnnotation();
// getProvider would work here too.
yourDep = injector.getInstance(Key.get(YourDep.class, annotation));
}
}
If you're trying write a Provider that takes a parameter, the best way to express this is to write a small Factory.
class YourDepFactory {
#Inject #A Provider<YourDep> aProvider;
#Inject #B Provider<YourDep> bProvider;
// and so forth
Provider<YourDep> getProvider(YourParameter parameter) {
if (parameter.correspondsToA()) {
return aProvider;
} else if (parameter.correspondsToB()) {
return bProvider;
}
}
YourDep get(YourParameter parameter) {
return getProvider(parameter);
}
}

Related

get annotation on method from a CDI managed bean

I want to retrieve an annotation (a custom written one) from a method. Usually I can ask the classloader by accessing
class.getMethod("methodName").getAnnotation("annotationName")
But if the bean is managed by a CDI container (I am using OpenWebBeans) the class is enhanced at runtime. Then I have to use the superclass to ask for annotations. Currently I try to detect if the class is managed by looking for "$$" in the classname. But that seems to be a very dirty solution to me.
Is there any good way to retrieve anntations from a CDI managed bean?
In detail my code is something like that:
I created an annotation "Coolnessfactor" to mark a method to be very cool :-)
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface Coolnessfactor {
CoolnessValue value();
}
Via the enumeration CoolnessValue I want to specify how cool the method implementation is.
public enum CoolnessValue {
POOR, VERY_COOL, UNBELIEVABLE;
}
Then I mark different methods in my business classe with this annotation, fe:
#Override
#Coolnessfactor(CoolnessValue.POOR)
public void getSingleObjectWithDetails(final Integer techId) {
return this.dao.findCompleteDataByPrimaryKey(techId);
}
Now I want to analyse the value of the annotation which marks the different method. I have to do it in a CDI-Decorator, therefore I cannot do it with an interceptor binding.
At the moment my approach is to use the reflection API to retrieve the annotation value:
public static <A extends Annotation> Map<String, A> getAnnotatedMethodsOfClass(final Class<?> clazz,
final Class<A> annotationClazz) {
final Map<String, A> annotationMap = new HashMap<String, A>();
Method[] declaredMethods;
if (clazz.getName().contains("$$")) {
declaredMethods = clazz.getSuperclass().getDeclaredMethods();
} else {
declaredMethods = clazz.getDeclaredMethods();
}
for (final Method m : declaredMethods) {
if (m.isAnnotationPresent(annotationClazz)) {
annotationMap.put(m.getName(), m.getAnnotation(annotationClazz));
}
}
return annotationMap;
}
But this looks very awful to me. Especcially the detection of a class which is enhanced by the CDI implementation is very bad.
Maybe try it with BeanManager - you will want to use it to get hold of a Bean<?> instance of your bean. The approaches differ here, based on what kind of bean it is. Shuffle through the API and find your way.
Once you get Bean<?> you should be able to use getBeanClass() and with that you gain access to methods and their annotations.

How to configure providers with custom parameters?

My class depends on some services which needs to take few parameters and then make network call, currently I am passing those parameters and then creating those services via a factory injected into my class. I need to inject those services as a dependency instead, I know that I can create providers for them but in most of the examples I see that the providers are often bound to the fixed values like serveraddres etc. but I need to give then values during run time.
Below is my example code:
public SomeClass {
private final SomeFactory someFactory;
#Inject
SomeClass(SomeFactory factory) {
someFactory = factory;
}
public Foo getFoo(String fooId) {
FooService fooService = someFactory.getFooService(fooId);
return fooService.getFoo();
}
}
What I need to do is:
public SomeClass {
private final FooService fooService;
#Inject
SomeClass(FooService fooService) {
this.fooService = fooService;
}
public Foo getFoo(String fooId) {
return fooService.getFoo();
}
}
Update 1
Making the use case more clear:
#Provides
#RequestScoped
public SomeService provideSomeService(Dep1 dep1, String code) throws IOException {
return new SomeService.Builder()
.withApplicationName("Foo")
.setCode(code)
.build();
}
Here, code can be null by default and when needed I can give some value in it.
Can I somehow pass arguments to the provider before its created?
If you have a binding for your value (here, code is a String without a binding annotation), then your Update 1 is exactly what the code would look like.
In practice, there are a few differences:
Constants like int and String values are generally annotated with a binding annotation, either #Named or a custom annotation.
If you need to inject a value into an object graph after Guice initialization, but have a deep enough object graph that dependency injection is still a good idea, you can create a child injector. This way you can make a #Named("code") String accessible within one action or object, but not across your entire Guice application.
If your value for code is dynamic enough that it can't be provided through Guice as a key of its own, then you'll have to pass it in using a factory of some sort. For a Builder-based object, I'd say that your SomeFactory implementation is the best that I would come up with in your case.
If you don't need to use a Builder, and can let Guice create the object based on your fields or constructor parameters, you can code-generate a Factory.
Guice can generate a factory for you through FactoryModuleBuilder, in a feature known as "assisted injection".
Google's other tool, AutoFactory, will code-generate a factory implementation that works in both Guice and Dagger. (It's bundled as "Auto", which includes a model object generator called AutoValue that also generates annotation implementations.)
I put a small demonstration of a child injector and assisted injection in my other SO answer here.
The best approach here is to parameterize the module and pass the parameter through to a provider that you create at runtime:
public class MyModule extends AbstractModule {
private final String code;
public MyModule(String code) {
this.code = code;
}
#Override public void configure() {
Provider<Dep1> depProvider = getProvider(Dep1.class);
bind(SomeService.class)
.toProvider(() -> new SomeService.Builder()
.withApplicationName("Foo")
.withDep(depProvider.get())
.setCode(code)
.build())
.in(RequestScoped.class);
}
}

Is it possible to use the Multibinder within Guice to construct dynamic sets based on application configuration?

I have an application which relies on Properties configuration to determine whether to mix in various components or not.
For example, the configuration has boolean flags like "componentX.enabled" etc which determine whether these components should be active or not.
Currently I am using these flags in my provider methods like so:
#Provides
#Singleton
#Nullable
public ComponentX provideComponentX(Properties props) {
if (props.isComponentXEnabled()) {
return new ComponentX();
} else {
return null;
}
}
#Provides
#Singleton
public Set<Component> provideComponentSet(
#Nullable ComponentX compX,
ComponentY compY,
ComponentZ compZ
) {
Set<Component> comps = new HashSet<>();
if (compX != null) {
comps.add(compX);
}
comps.add(compY);
comps.add(compZ);
return comps;
}
This approach seems a little clunky (it relies on possible injecting null)- but is there a better way?
The only other way I can think of doing it is by using a parent injector to obtain the application Properties into my module, and then using the set Multibinder.
Then use the create child injector with the new module to complete the bootstrap process.
public class Module extends AbstractModule {
Properties props;
public Module(Properties props) {
this.props = props;
}
public void configure() {
Multibinder<Component> compBinder = Multibinder.newSetBinder(binder(), Component.class);
if (props.isComponentXEnabled()) {
compBinder.addBinding().to(ComponentX.class);
}
compBinder.addBinding().to(ComponentY.class);
compBinder.addBinding().to(ComponentZ.class);
}
}
This also seems a little clunky because it requires the use of a child injector etc.
Again, is there a better way?
Maybe I could use Netflix's Governator (https://github.com/Netflix/governator/wiki/Configuration-Mapping) to inject Configuration values into my module (not sure if that is possible or not)?
How do other people approach this problem?
The applications I've been working with recently have a properties file (or other configuration) that is used to decide which parts of the application are relevant. Our typical approach is parse those properties immediately (just to a Properties object) and construct the application module(s) from that, and they will then conditionally include other modules based on the values specified.
In a couple of places, this has grown into an "init parameters" set, with an enumeration of possible parameters:
enum InitParam {
PricesQueue("prices.queue")
}
Each enum instance is related to a property key and there is a method to get a basic string value for each parameter from Properties:
boolean presentIn(Properties props) { return props.containsKey(propertyKey); }
String valueIn(Properties props) { return props.getProperty(propertyKey); }
So this can be used like so:
public AppModule extends AbstractModule {
private final Properties config;
protected void configure() {
if (InitParam.PricesQueue.presentIn(config)) {
install(new PricesQueueConsumerModule(config));
}
}
}
Additionally, there is a module to bind all the values in the config properties to String, Optional<String> etc, allowing:
#Inject
public PricesQueueConsumer(#FromInitParam(InitParam.PricesQueue) String queueName) {
}
This will trap the queue consumer being referenced when the configuration isn't available (the module won't bind a string if the value isn't present in the config file) while still allowing the behaviour for when the value isn't present to be deferred to later (by injecting Optional<String> instead)
So this is somewhat similar to your second approach, except that I'd not considered the using-Guice-to-inject-Guice-modules approach, which seems a bit convoluted. Although probably it's essentially the same. Maybe rather than a parent/child injector you could simply create a "bootstrapping" injector to build your top-level application module, and then use that to build a completely separate injector?

Multiple implementations to a service using Guice using providers

I need a suggestion for how to code for multiple implementations for a service using Google-guice. Below is the example
TestService testService =new TestServiceImplOne();
TestService testService =new TestServiceImplTwo();
As Guice doesn't allow binding a type to more than one implementations as the below code results in error
binderObject.bind(SomeType.class).to(ImplemenationOne.class);
binderObject.bind(SomeType.class).to(ImplemenationTwo.class);
we can solve this with named annotations as below
binder.bind(Player.class).annotatedWith(Names.named("Good")).to(GoodPlayer.class);
binder.bind(Player.class).annotatedWith(Names.named("Bad")).to(BadPlayer.class);
#Named("Good") Player goodPlayer = (Player)injector.getInstance(Player.class);
#Named("Bad") Player badPlayer = (Player)injector.getInstance(Player.class);
But the application which iam working is something like this. We are binding all the modules in the init() method and creating the injector modules:
//separate method to bind
protected void configure() {
bind(new TypeLiteral<List<Service>>() {}).toInstance(serviceSets);
}
//separate method to inject
Injector i = Guice.createInjector(modules);
But with the above process I can just bind one implementation class to the interface (service class)
Could you please provide me a way to do this with providers. I would like to do something like this below
class TestServiceProvider extends Provider{
// some code where it returns the instance of impl class needed. In my case TestServiceImplOne and TestServiceImplTwo and provider returns the corresponding instance of service class
}
and bind service class with provider class. Something like this
bind(TestService.class).toProvider(TestServiceProvider.class);
I would appreciate if someone suggests a good example using providers or some other way that I can inject whatever implementation I want in the client.
Note: I am using webservices and I am not sure how I can inject different implementations when a webservice is called to a service class.
First of all thanks very much for responding . Coming straight to the point
Iam working on webservices . Heres's the Flow
// GET URI
GET http://www.google.com:8182/indi/provide/organizations/{ou}
OrganizationsResource -------->OrganizationService------>OrganizationServiceImpl
Iam binding OrganizationService with OrganizationServiceImpl and injecting the OrganizationService in OrganizationsResource
#Inject
public void setOrganizationService(OrganizationService orgService) {
this.orgService= orgService;
}
Its fine till here but i have two implementations for OrganizationService ------>OrgDeatilsServiceImpl which does some other job
Now i want to bind both OrganizationServiceImpl and OrgDeatilsServiceImpl to OrganizationService
Confusions:
1) What procedure i have to use in Guice to bind two implementaions?
2) How exactly i can code in OrganizationsResource to dynamically decide which implementation to call.
I would appreciate if you give a sample example for the above requirement.
As Vladimir noted, you can use binding annotations with Providers...
// in YourModule.configure():
bind(TestService.class)
.annotatedWith(Names.named("foo")
.toProvider(TestServiceProvider.class);
...and generic types using TypeLiterals...
bind(new TypeLiteral<List<Service>>() {})
.annotatedWith(Names.named("bar")
.toInstance(serviceSets);
...as long as you ask for an annotated instance using getInstance(Key<T>)...
List<Service> servicesOne = injector.getInstance(
new Key<List<Service>>(Names.named("bar")) {});
// or
List<Service> servicesTwo = injector.getInstance(
Key.get(new TypeLiteral<List<Service>>() {}, Names.named("bar"));
...or, preferably, keep them as fields and let Guice do the injecting, because Guice can't inject local variables. Remember that Guice can only inject classes that it creates, or that you request specifically.
class MyInjectorCreator {
#Inject #Named("foo") Provider<TestService> fooServiceProvider;
#Inject #Named("bar") List<Service> barServices;
// Guice will also wrap/unwrap Providers automatically.
#Inject #Named("foo") TestService fooService;
#Inject #Named("bar") Provider<List<Service>> barServicesProvider;
public void createInjector() {
Injector injector = Guice.createInjector(getListOfModules());
injector.injectMembers(this);
}
}
Now, that answers the question as you phrased it in the title. That said, it sounds like you actually want to choose between implementations at runtime, which is a slightly different but easy-to-solve problem:
class TestServiceProvider extends Provider<TestService> {
// Injection is allowed here!
#Inject ApplicationSettings settings;
#Inject Provider<TestServiceImplOne> oneProvider;
#Inject Provider<TestServiceImplTwo> twoProvider;
#Override public TestService get() {
if (settings.isInTestMode()) {
return new TestTestServiceImplImpl(); // without injection!
} else if (settings.useNewService()) {
return twoProvider.get(); // with injection!
} else {
return oneProvider.get(); // also with injection!
}
}
}
But I should warn you that if you know at injector creation time which service to use, you should probably just bind it correctly then for the sake of code cleanliness and ease of readability:
// in YourModule.configure():
if (settings.isInTestMode()) {
bind(TestService.class).toInstance(new TestTestServiceImplImpl());
} else if (settings.useNewService()) {
bind(TestService.class).to(TestServiceImplTwo.class);
} else {
bind(TestService.class).to(TestServiceImplOne.class);
}

Guice: is it possible to inject modules?

I have a Module that requires some Depedency. Is there a way Modules themselves can be injected? I realize this is a bit of a chicken and egg situation...
Example:
public class MyModule implements Module {
private final Dependency d_;
#Inject public MyModule(Dependency d) {
d_ = d;
}
public void configure(Binder b) { }
#Provides Something provideSomething() {
// this requires d_
}
}
I suppose in this case the solution would be to turn the #Provides method into a full-fledged Provider<Something> class. This is clearly a simplified example; the code I'm dealing with has many such #Provides methods so cutting them each into individual Provider<...> classes and introducing a module to configure them adds a fair amount of clutter - and I thought Guice was all about reducing boilerplate clutter?
Perhaps it's a reflection of my relative noobyness to Guice but I've come across a fair few cases where I've been tempted to do the above. I must be missing something...
#Provides methods can take dependencies as parameters just like parameters to an #Inject annotated constructor or method:
#Provides Something provideSomething(Dependency d) {
return new Something(d); // or whatever
}
This is documented here, though perhaps it could be made to stand out more.
Using a provider or #Provides methods are great if you need a dependency to manually construct an object. However, what if you need something to help you decide how to configure the bindings themselves? It turns out you can use Guice to create (and configure) your module.
Here is a (contrived) example. First, the module we want to configure:
/**
* Creates a binding for a Set<String> which represents the food in a pantry.
*/
public class PantryModule extends AbstractModule {
private final boolean addCheese;
#Inject
public ConditionalModule(#Named("addCheese") boolean addCheese) {
this.addCheese = addCheese;
}
#Override
protected void configure() {
Multibinder<String> pantryBinder = Multibinder
.newSetBinder(binder(), String.class);
pantryBinder.addBinding().toInstance("milk");
if (addCheese) {
pantryBinder.addBinding().toInstance("cheese");
}
pantryBinder.addBinding().toInstance("bread");
}
}
The PantryModule expects a boolean value to be injected to decide whether or not it should include cheese in the pantry.
Next, we'll use Guice to configure the module:
// Here we use an anonymous class as the "configuring" module. In real life, you would
// probably use a standalone module.
Injector injector = Guice.createInjector(new AbstractModule() {
#Override
protected void configure() {
// No cheese please!
bindConstant().annotatedWith(Names.named("addCheese")).to(false);
bind(PantryModule.class);
}
});
Module configuredConditionalModule = injector.getInstance(PantryModule.class);
Now that we have a configured module, we'll update our injector to use it...
//...continued from last snippet...
injector = injector.createChildInjector(configuredConditionalModule);
And finally we'll get the set of strings that represent our pantry:
//...continued from last snippet...
Set<String> pantry = injector.getInstance(new Key<Set<String>>() {});
for (String food : pantry) {
System.out.println(food);
}
If you put all the pieces together in a main method and run it, you'll get the following output:
milk
bread
If you change the binding to the "addCheese" boolean to true, you'll get:
milk
cheese
bread
This technique is cool, but probably only useful when you have control over the Injector instance and only when the module requires complex dependencies. Nonethless, I found a real need for this on a real project at work. If I did, then someone else might too.
The question is already well answered, but I just wanted to add a variation to Colin's example:
class MyModule extends AbstractModule {
public void configure() {
bind(Something.class).toProvider(new Provider<Something>() {
#Inject Dependency d;
Something get() { return d.buildSomething(); }
}
}
}
The #Provides method approach is clearer than what I have above for this simple case, but I've found that instantiating an actual Provider can be useful in some situations too. Something I stole from the mailing list; wouldn't have occurred to me on my own ;)
What is the problem with initializing the module just by calling new MyModule(d) or by creating a Provider<Something> that has an injected Injector? Those would appear to be the standard ways of handling this sort of problem. As has been mentioned, you can also use #Provides methods with arguments.
If the dependency is optional then you can create the module and then call a setter to initialize the value if needed (e.g., com.google.inject.persist.jpa.JpaPersistModule does this with properties, while using new JpaPersistModule(String) to load the correct configuration).
Otherwise I suppose it might be possible to do so (and then call createChildInjector(Modules... modules)), but I'd almost always prefer one of the other approaches to that one.

Categories

Resources