how to use guice injector in a guice provider? - java

I'm using guice to inject dependencies.
I have this provider:
public class RequestUrlRepository implements Provider<IRequestUrlRepository> {
#Singleton
#Override
public IRequestUrlRepository get() {
IRequestUrlRepository answer = null;
if (System.getProperty("").equals(RouteOrCostRequest.cost.toString())){
answer = new CostRequestUrlRepository(...);
}
else
{
answer = new RoutingRequestUrlRepository(...);
}
return answer;
}
}
how can I use guice injector to fill new CostRequestUrlRepository(...); and new RoutingRequestUrlRepository(...) when it's in a provider?
If not possible, how can I init them without manually creating all the ctor's params?

Providers can accept #Inject-annotated constructors and fields, and Guice's built-in bindings will let you inject both Injector and a Provider for any key the injector can provide (e.g. Provider<CostRequestUrlRepository>).
#Singleton
public class RequestUrlRepository implements Provider<IRequestUrlRepository> {
#Inject Provider<CostRequestUrlRepository> costRepositoryProvider;
#Inject Provider<RoutingRequestUrlRepository> routingRepositoryProvider;
#Inject Injector injector;
#Override public IRequestUrlRepository get() {
IRequestUrlRepository answer = null;
if (System.getProperty("").equals(RouteOrCostRequest.cost.toString())){
return costRepositoryProvider.get();
} else {
return routingRepositoryProvider.get();
}
// Alternatively:
return injector.getInstance(Class.forName(System.getProperty("")));
}
}
Note that the #Singleton annotation goes on the class, not the method; per the Guice mailing list "Scope annotations apply to providers as a whole, annotating the get() method with #Singleton is erroneous and ignored." (link).
Ideally, rather than injecting the entire injector, you should inject each provider; this should make it easier to see your system's dependencies, and then you're relying less on Guice and more on the general JSR330 annotations. However, if you have to instantiate an arbitrary class based on a name or Class literal in a variable, then injecting the Injector is the way to go.

Related

Guice Inject Field in class NullPointerException, circular dependency issue introduced

I need to use create a singleton in Guice defined in separate library.
#RequiredArgsConstructor
public class Operator {
#NonNull private final Catalog catalog;
#Inject private Evaluator evaluator;
...
}
One of the problem is that this class introduces circular dependency, Evaluator -> Operator -> Evaluator. I know it is not a good design, but is consumed by other packages, there is no easy way to change it. This library has the beans created using Spring framework, where this circular dependency could be handled.
Now I need to create an instance of the Operator in a service based on Guice, I have created the singleton Evaluator in the service, but it was not able to inject the singleton into the Operator.
#Provides #Singleton
public Operator operator(final Catalog catalog)
{
return new Operator(catalog);
}
#Provides #Singleton
public Evaluator evaluator(final Operator operator) {
return new Evaluator(operator);
}
Since the Operator class is being used for other services based on Spring framework, I would prefer not to change it. What can I do to make the Guice able to inject the Evaluator into Operator?
Thanks in advance for any help!
Try this, I hope it will help you.
public class Evaluator {
#Inject public Evaluator(Operator op) {
// ...
}
}
public class Operator {
#Inject public Operator(map m) {
// ...
}
}
public class map {
#Inject public map(Provider<Evaluator> EvaluatorProvider) {
// ...
}
}
In this circular dependency case, Guice is not smart enough to help injecting dependencies, you can specifically ask Guice to inject dependencies for this class.
#Provides #Singleton
public Operator operator(final Catalog catalog)
{
return new Operator(catalog);
}
And then injector.injectMembers(injector.getInstance(Operator.class)) would help inject the required dependencies.

Guice FactoryModuleBuilder an instance with constructor parameters

I´m using Guice to initalize a class with some arguments from a config file
#Provides
#Singleton
RetryServiceCaller provideMaxRetryAttempts(#Named("config") JsonObject config) throws IOException {
JsonObject retryDetails = config.getJsonObject("retry_details");
return new RetryServiceCaller(retryDetails.getInteger("maxRetryAttempts"), retryDetails.getInteger("upperBoundary"), retryDetails.getInteger("lowerBoundary"),
retryDetails.getLong("multiplicationFactor"), retryDetails.getInteger("timeout"), retryDetails.getInteger("increaseTimeout"));
}
This class is injected in another class which is singleton as well.
class A{
#Inject private RetryServiceCaller retryServiceCaller;
}
But now the problem is that since this new class A is singleton, I need to clone the retryServiceCaller every time that somebody use this class A.
I´ve been investigating FactoryModuleBuilder to use it and create a factory for this class. But since the class has parameters from the config file I could not find the way to make it works.
Something like this
class A{
#Inject private RetryServiceCaller.Factory retryServiceCallerFactory;
}
Then in my RetryServiceCaller implement this
public interface Factory {
#Inject
RetryServiceCaller create();
}
#Inject
public RetryServiceCaller(int maxRetryAttempts, int upperBoundary, int lowerBoundary, long multiplicationFactor, int timeout, int incrementTimeout) {
this.maxRetryAttempts = maxRetryAttempts;
this.upperBoundary = upperBoundary;
this.lowerBoundary = lowerBoundary;
this.multiplicationFactor = multiplicationFactor;
this.timeout = timeout;
this.incrementTimeout = incrementTimeout;
}
But guice throw me errors saying
No implementation for com.proxy.handlers.RetryServiceCaller$Factory was bound
Guice can automatically provide a zero-argument factory: Instead of injecting Foo, you can always inject Provider<Foo>. This allows you to call fooProvider.get() to create an instance whenever and wherever you'd like. You don't have to bind to a Provider or use a Provides method to get access to this; you can inject Foo or Provider<Foo> whether you use a bind(...).to(...) type binding, a toProvider binding, a toInstance binding, a #Provides method, or anything else, and Guice will call get or return an internal Provider automatically.
(The returned Provider will also respect scopes, so you'll need to drop your #Singleton scope in order to get more than one instance, and be aware that toInstance bindings will always return the same instance.)
This is not a job for FactoryModuleBuilder; only use FactoryModuleBuilder when you need to mix injected and non-injected constructor parameters in the same type.
Your finished binding should look like this:
#Provides
/* NOT #Singleton */
RetryServiceCaller provideMaxRetryAttempts(#Named("config") JsonObject config) throws IOException {
JsonObject retryDetails = config.getJsonObject("retry_details");
return new RetryServiceCaller(retryDetails.getInteger("maxRetryAttempts"), retryDetails.getInteger("upperBoundary"), retryDetails.getInteger("lowerBoundary"),
retryDetails.getLong("multiplicationFactor"), retryDetails.getInteger("timeout"), retryDetails.getInteger("increaseTimeout"));
}
And in your class:
#Inject public YourCallerConsumer(Provider<RetryServiceCaller> callerProvider) {
this.callerProvider = callerProvider;
}
public void doAction() {
RetryServiceCaller newCaller = callerProvider.get();
// interact with caller
}
Your first approach should work just fine. If you don't want the RetryServiceCaller to be a singleton, remove the #Singleton annotation from the provider method, and a new instance will be created for every injection point.
Assisted inject could work here too, but it's overkill. If you want to go that route:
interface RetryServiceCallerFactory {
RetryServiceCaller create(String configParam1, String configParam2);
}
public class RetryServiceCaller {
#AssistedInject
public RetryServiceCaller(String configParam1, String configParam2) {}
}
then, in your module
install(new FactoryModuleBuilder().build(Factory.class);
and in your injection points
#Inject RetryServiceCallerFactory factory;
RetryServiceCaller create(JsonObject config) {
return factory.create(config.getFirstParam(), config.getSecondParam());
}
You can refer to the documentation for more extensive examples.

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);
}
}

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);
}

Inject cached instances using cdi

I want expose instances managed by an external framework to CDI applications using #Inject. These instances must be provided this other framework since their lifecycle is based on various caching strategies.
Ex: same instance is visible within same thread scope, might live across many request scopes, session scope is not applicable. Seems I need to define a new scope targeting these kind of instances?
What is the best way to do this? An extension, is it possible with producer methods?
I almost got it to work with producer methods using the following:
#Inject
#CustomInject
FwObject obj;
#Produces
#CustomInject
FwObject createConfig(InjectionPoint p) {
return (FwObject) ctx.get((Class<?>) p.getType());
}
But this force me to be explicit about the type produced which is not possible since there is no common framework interface.
Any help appreciated.
Maybe with producer methods, all depends on what you need, but an extension is probably the best way to go. If you need to go with a new scope (if you're using JSF the Conversation scope may work) you will certainly need to create an extension.
I think I solved it by creating a custom scope. The following article was really helpful:
http://www.verborgh.be/articles/2010/01/06/porting-the-viewscoped-jsf-annotation-to-cdi/
This is a very brief description of how I solved it.
Create custom scope annotation.
import javax.enterprise.context.NormalScope;
#Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
#Target({ ElementType.TYPE, ElementType.METHOD })
#NormalScope
public #interface CustomScope {
}
Create custom context.
import javax.enterprise.context.spi.Context;
public class CustomContext implements Context {
private MyFw myFw = .... ;
#Override
public Class<? extends Annotation> getScope() {
return CustomScope.class;
}
#Override
public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) {
Bean bean = (Bean) contextual;
return (T) myFw.get(bean.getBeanClass());
}
#Override
public <T> T get(Contextual<T> contextual) {
Bean bean = (Bean) contextual;
return (T) myFw.get(bean.getBeanClass());
}
#Override
public boolean isActive() {
return true;
}
}
Create extension and register context.
import javax.enterprise.inject.spi.Extension;
public class CustomContextExtension implements Extension {
public void afterBeanDiscovery(#Observes AfterBeanDiscovery event, BeanManager manager) {
event.addContext(new CustomContext());
}
}
Register extension.
Add CustomContextExtension to META-INF/javax.enterprise.inject.spi.Extension
Add CustomScope to framework object.
#CustomScope
public class FwObject { ... }
Inject FwObject using #Inject where needed.
public class MyService {
#Inject
FwObject obj;
}

Categories

Resources