I need some help with Spring (SpringBoot 1.3.2.RELEASE, Spring 4.3.11.RELEASE).
Use case is special and need explanations.
I've got a Spring app managing requests send by customers. In order to process these requests, we need to use services declared with #Autowired annotation. Very classic.
Recently, we decided to process new types of requests from other countries.
The point is that to face the different cases and types of requests, we decided to implement a Strategy Pattern.
-> Depending on the type of request, we execute a strategy which is selected at run time. Each strategy is contained in a concrete class and all strategies share a same Interface.
So, I had :
a main class in which requests processing was completely done. To do its job, this class used to call somes services declared with #Autowired annotation.
Now I have :
a main class in which requests processing is only initialized. To do
its job, this class will instantiate at runtime a single strategy depending on some criterias.
a IStrategy (interface) with 2 methods thats will be implemented
by my 2 concrete classes
2 concrete classes (and more to come) that will do the job. The very important point is that these concrete classes will be instantiated at runtime, AFTER the Spring context is loaded.
The problem is that after the Spring context is loaded, it's not possible anymore to use the #Autowired annotation.
All services I wanted to use in my concrete strategy classes can not be called by #Autowired any more and remain NULL.
I found a workaround by passing services I need as argument to my concrete strategy classes, but the number of services I have to pass as argument vary from one strategy to another.
I think I should pass the whole Spring context instead but I don't know how to do that. And I also don't know how I could access to all annotated services from the context.
PS : I do not show lines of code because I think there's no need actually. If you consider it would be more explicit with code, I will send some.
Thanx by advance.
Instead of declaring the services as bean, you should declare a factory to map the dependencies, it will inspect the request before returning the concrete instance of the service to the injector.
take a look here:
https://grokonez.com/spring-framework/spring-core/use-spring-factory-method-create-spring-bean
You can use below class to get Application Context and Beans statically
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;
#Service
public class BeanUtil implements ApplicationContextAware {
private static ApplicationContext context;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static <T> T getBean(Class<T> beanClass) {
return context.getBean(beanClass);
}
}
Hello to all of you who answered me very quickly.
First of all, I have to apologize for answering so lately to all your comments. Last sprint was a big load and the new one is not better ^^
My need was to create on object after the Spring context has finished to create and load all parts of the app.
As part of a Strategy pattern, I have to instanciate a class at runtime depending on some values found in the request file I have to process. This class needs many services declared with the #Autowired annotation, but all the autowired objects remained 'null' because called after the context was loaded.
Here is the code I first wanted to use.
It was OK without Spring.
Function<Document, IStrategy> func = doc -> {
String strategyToApply = "";
IStrategy strategy = null;
switch(doc.getPlace()) {
case "Paris":
strategyToApply = "strategies_classes.ProcessParis";
break;
case "New York":
strategyToApply = "strategies_classes.ProcessNewYork";
break;
}
case "Roma":
...
try {
**Class<?> classToUse = Class.forName(strategyToApply);
strategy = (IStrategy) classToUse.newInstance();**
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return strategy;
};
Consumer<Document> consumerStrategy = doc -> {
IStrategy strategy = func.apply(doc);
strategy.bookRequest(doc);
};
documents.stream()
.forEach(consumerStrategy);
I finally found THE magic object. It is a good workaround when Spring object's lifecycle is not compliant with our own conception.
To use it, you just have to declare it with #Autowired :
#Autowired
private AutowireCapableBeanFactory autowireBeanFactory;
Note that the AutowireCapableBeanFactory is a Spring object you don't need to declare anywhere else !!
Then, to use it, simple (I designed a brand new service very different from what you saw above, but it's doing the same) :
public <T> T getStrategyToUse(Entity bookingCtr, Funder funder, StrategyEnum strategy) throws FunctionalException {
String strategyToApply = null;
strategyToApply = strategyDao.getClassToApply(bookingCtr, funder, strategy);
Class<?> classToUse;
try {
classToUse = Class.forName(strategyToApply);
T strat = (T) **autowireBeanFactory.getBean**(classToUse);
return (T) strat;
} catch (ClassNotFoundException e) {
LOGGER.error("The indicated Strategy class was not found", e);
}
return null;
}
When loaded at runtime, the chosen class will be instanciated without any problem and ALL of its autowired objects won't be null anymore.
I hope this will help.
Related
Say I have some Java class named SomeClassConfig in which I want to define a dependency injection like the following;
#Configuration
public class SomeClass {
#Bean
SomeOtherClass someOtherClass() {
FactoryClass factory = UtilFactoryClass.getDefaultFactory();
return factory.create();
}
}
Here UtilFactoryClass denotes some library that allows me to create a factory class, which in turn allows me to create an instance of the object I am interested in. My problem is that the above-mentioned default factory is initialized after some time, so I would like for the bean to be instantiated / injected after the instantiation the default FactoryClass instance. Is this possible? UtilFactoryClass has no knowledge of the Spring Boot framework, and I tried to apply the #DependsOn annotation, but realized it only allows for me to depend on other Beans.
The concrete 'getDefaultFactory' method I am trying to apply is the following: Link. It is associated to a library named Keycloak. My problem is that the factory obtained from this method is null until a certain point in the life cycle of the application.
Do you mean:
#Configuration
public class SomeClass {
#Bean
SomeOtherClass someOtherClass() { //argument injection also possible
return factory().create();
}
#Bean
FactoryClass factory() {
//check/wait for condition e.g.:
while (!UtilityFactory.isInitialized()) {
try {
Thread.sleep(1000);
// better: TimeUnit.XXX.sleep(), and even better use an (spring managed) executor
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
return UtilFactoryClass.getDefaultFactory();
}
}
"Let spring manage the factory"!? ;)
For the check/wait part, see: https://www.baeldung.com/java-delay-code-execution
I want to return multiple spring beans based on the condition in the factory class.
Is this a good practice?
Any better ways to write the following piece of code?.
Any other design patterns suitable here?
Below is the code snippet:
package com.test;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
#Component
public class InstanceFactory {
#Resource(name = "instance1")
private Instance instance1;
#Resource(name = "instance2")
private Instance instance2;
public Instance getService(Condition condition) {
if (condition.one() && condition.two()) {
return instance2;
} else {
return instance1;
}
}
}
It depends on what you want to achieve. Factory Pattern is meant to create objects but what you are returning are objects already create somewhere else (Spring in this case). If you want to create beans that will be managed by Spring there are several ways:
#Conditional(YourConditionImplementation.class): This annotation added on a method of a #Configuration annotated class will allow you to create a bean when the given condition is fullfilled. Example here: https://javapapers.com/spring/spring-conditional-annotation/
You can uses as well BeanFactory to inject the definition of your bean (DefinitionBean) into the container. Example here: https://www.logicbig.com/tutorials/spring-framework/spring-core/bean-definition.html
Now, if you want an object that determine what object of type Instance fits better for some need then your approach is ok, but it is not technically a factory :)
When designing something like that I would face that solution considering two design patterns:
Strategy pattern: In order to replace repetitive if else every time you need to evaluate more instances.
Decorator pattern: Trying to make every condition as configurable as possible. They can be composed (decorated) for one or more predicates.
Considering these two pattens you might achieve something like this:
First, define which conditions will identify a given instance:
public enum InstanceType {
INSTANCE_TYPE_1(Condition::isOne, Condition::isTwo),
INSTANCE_TYPE_2(Condition::isOne, Condition::isThree),
...;
private List<Predicate<Condition>> evaluators;
#SafeVarargs
InstanceType(final Predicate<Condition>... evaluators) {
this.evaluators = Arrays.asList(evaluators);
}
public boolean evaluate(final Condition condition) {
return evaluators.stream().allMatch(it -> it.test(condition));
}
}
Then, you should link every instance implementation to an specific instance type:
#Component
public class InstanceOne implements Instance {
#Override
public InstanceType getType() {
return InstanceType.INSTANCE_TYPE_1;
}
}
Finally, a class to config where defining the relation between types and instances as EnumMap
#Configuration
public class InstanceFactoryConfig {
#Autowired
private List<Instance> instances;
#Bean
public EnumMap<InstanceType, Instance> instancesMap() {
EnumMap<InstanceType, Instance> instanceEnumMap = new EnumMap<>(InstanceType.class);
instances.forEach(i -> instanceEnumMap.put(i.getType(), i));
return instanceEnumMap;
}
}
Thus, you InstanceFactory can be replaced to something like this:
public class InstanceFactory {
#Autowire
private final EnumMap<InstanceType, Instance> instancesMap;
public void getInstance(Condition condition) {
instancesMap.get(getInstanceType(condition)).doSomething();
}
private InstanceType getInstanceType(Condition condition) {
return Arrays.stream(InstancesType.values())
.filter(evaluator -> evaluator.evaluate(condition))
.findFirst().orElseThrow(() -> new RuntimeException("Instance type not found"));
}
}
As you can see, you InstanceFactory is less prone to be modified. This means, every time you need you add a new instance implementation you only need to modify the InstanceType enum. Hope this is helps.
You can use spring existing FactoryBean interface and implement your own logic
It’s one of the best approaches to create beans in spring framework
Here is the link with example :
https://www.baeldung.com/spring-factorybean
See:
Spring Profile
The active profile is set by properties and based on the value you assign to the profile, Spring will load different beans for the same interface.
So it might be exactly what you need.
I am working on a REST API where I have an interface that defines a list of methods which are implemented by 4 different classes, with the possibility of adding many more in the future.
When I receive an HTTP request from the client there is some information included in the URL which will determine which implementation needs to be used.
Within my controller, I would like to have the end-point method contain a switch statement that checks the URL path variable and then uses the appropriate implementation.
I know that I can define and inject the concrete implementations into the controller and then insert which one I would like to use in each particular case in the switch statement, but this doesn't seem very elegant or scalable for 2 reasons:
I now have to instantiate all of the services, even though I only need to use one.
The code seems like it could be much leaner since I am literally calling the same method that is defined in the interface with the same parameters and while in the example it is not really an issue, but in the case that the list of implementations grows ... so does the number of cases and redundant code.
Is there a better solution to solve this type of situation? I am using SpringBoot 2 and JDK 10, ideally, I'd like to implement the most modern solution.
My Current Approach
#RequestMapping(Requests.MY_BASE_API_URL)
public class MyController {
//== FIELDS ==
private final ConcreteServiceImpl1 concreteService1;
private final ConcreteServiceImpl2 concreteService2;
private final ConcreteServiceImpl3 concreteService3;
//== CONSTRUCTORS ==
#Autowired
public MyController(ConcreteServiceImpl1 concreteService1, ConcreteServiceImpl2 concreteService2,
ConcreteServiceImpl3 concreteService3){
this.concreteService1 = concreteService1;
this.concreteService2 = concreteService2;
this.concreteService3 = concreteService3;
}
//== REQUEST MAPPINGS ==
#GetMapping(Requests.SPECIFIC_REQUEST)
public ResponseEntity<?> handleSpecificRequest(#PathVariable String source,
#RequestParam String start,
#RequestParam String end){
source = source.toLowerCase();
if(MyConstants.SOURCES.contains(source)){
switch(source){
case("value1"):
concreteService1.doSomething(start, end);
break;
case("value2"):
concreteService2.doSomething(start, end);
break;
case("value3"):
concreteService3.doSomething(start, end);
break;
}
}else{
//An invalid source path variable was recieved
}
//Return something after additional processing
return null;
}
}
In Spring you can get all implementations of an interface (say T) by injecting a List<T> or a Map<String, T> field. In the second case the names of the beans will become the keys of the map. You could consider this if there are a lot of possible implementations or if they change often. Thanks to it you could add or remove an implementation without changing the controller.
Both injecting a List or a Map have some benefits and drawbacks in this case. If you inject a List you would probably need to add some method to map the name and the implementation. Something like :
interface MyInterface() {
(...)
String name()
}
This way you could transform it to a Map<String, MyInterface>, for example using Streams API. While this would be more explicit, it would polute your interface a bit (why should it be aware that there are multiple implementations?).
When using the Map you should probably name the beans explicitly or even introduce an annotation to follow the principle of least astonishment. If you are naming the beans by using the class name or the method name of the configuration class you could break the app by renaming those (and in effect changing the url), which is usually a safe operation to do.
A simplistic implementation in Spring Boot could look like this:
#SpringBootApplication
public class DynamicDependencyInjectionForMultipleImplementationsApplication {
public static void main(String[] args) {
SpringApplication.run(DynamicDependencyInjectionForMultipleImplementationsApplication.class, args);
}
interface MyInterface {
Object getStuff();
}
class Implementation1 implements MyInterface {
#Override public Object getStuff() {
return "foo";
}
}
class Implementation2 implements MyInterface {
#Override public Object getStuff() {
return "bar";
}
}
#Configuration
class Config {
#Bean("getFoo")
Implementation1 implementation1() {
return new Implementation1();
}
#Bean("getBar")
Implementation2 implementation2() {
return new Implementation2();
}
}
#RestController
class Controller {
private final Map<String, MyInterface> implementations;
Controller(Map<String, MyInterface> implementations) {
this.implementations = implementations;
}
#GetMapping("/run/{beanName}")
Object runSelectedImplementation(#PathVariable String beanName) {
return Optional.ofNullable(implementations.get(beanName))
.orElseThrow(UnknownImplementation::new)
.getStuff();
}
#ResponseStatus(BAD_REQUEST)
class UnknownImplementation extends RuntimeException {
}
}
}
It passes the following tests:
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
public class DynamicDependencyInjectionForMultipleImplementationsApplicationTests {
#Autowired
private MockMvc mockMvc;
#Test
public void shouldCallImplementation1() throws Exception {
mockMvc.perform(get("/run/getFoo"))
.andExpect(status().isOk())
.andExpect(content().string(containsString("foo")));
}
#Test
public void shouldCallImplementation2() throws Exception {
mockMvc.perform(get("/run/getBar"))
.andExpect(status().isOk())
.andExpect(content().string(containsString("bar")));
}
#Test
public void shouldRejectUnknownImplementations() throws Exception {
mockMvc.perform(get("/run/getSomethingElse"))
.andExpect(status().isBadRequest());
}
}
Regarding two of your doubts :
1. Instantiating the service object should not be an issue as this is one time job and controller gonna need them to serve all type of request.
2. You can use the exact Path mapping to get rid of switch case. For e.g. :
#GetMapping("/specificRequest/value1")
#GetMapping("/specificRequest/value2")
#GetMapping("/specificRequest/value3")
All of the above mapping will be on separate method which would deal with specific source value and invoke respective service method.
Hope this will help to make code more cleaner and elegant.
There is one more option of separating this on service layer and having only one endpoint to serve all types of source but as you said there is different implementation for each source value then it says that source is nothing but a resource for your application and having separate URI/separate method makes the perfect sense here. Few advantages that I see here with this are :
Makes it easy to write the test cases.
Scaling the same without impacting any other source/service.
Your code dealing the each source as separate entity from other sources.
The above approach should be fine when you have limited source values. If you have no control over source value then we need further redesign here by making source value differentiate by one more value like sourceType etc. and then having separate controller for each group type of source.
Suppose I've a class Fruit and it's two subclasses - Apple and Grape:
class Fruit {
public void grind() { }
}
class Apple extends Fruit { }
class Grape extends Fruit { }
In spring properties file, I've a property that decides which bean to register at startup. At a time, I'll only have either Apple or Grape instance registered as a bean. The property is:
# This can be either apple or grape
app.fruit = apple
In the Java configuration file, I'm binding a String attribute using #Value with this property, and based on that, I'll create appropriate instance. I'm trying to use factory pattern here. So, I've a FruitFactory like this:
class FruitFactory {
private Map<String, Fruit> map = new HashMap<String, Fruit>();
public FruitFactory() {
map.put("apple", new Apple());
map.put("grape", new Grape());
}
public Fruit getFruit(String fruit) {
return map.get(fruit);
}
}
And here's my spring configuration class:
class SpringConfig {
#Value("${app.fruit}")
private String fruitType;
#Bean
public FruitFactory fruitFactory() {
return new FruitFactory();
}
#Bean
public Fruit getFruit() {
return fruitFactory().getFruit(fruitType);
}
}
So, here're my few questions:
Will the instances stored in the map inside the factory be spring managed bean? Is there any issue with the implementation? I've tried it, and it is working fine, and I'm confused whether the instances are really spring managed.
I was trying to implement it in a better way, so that when a new fruit comes, I don't have to modify my factory. On way is to provide a register() method in factory and let all the Fruit subclasses invoke it. But the issue is when and how the subclasses will be loaded? I'll not be using the classes, not before putting their instances into the map. Can anyone suggest a better way?
Edit:
As suggested in comment and answer, I've tried using #Profile instead of factory pattern. But I'm facing some issues in that. Here's what I've:
#Configuration
#Profile("apple")
class AppleProfile {
#Bean
public Fruit getApple() {
return new Apple();
}
}
#Configuration
#Profile("grape")
class GrapeProfile {
#Bean
public Fruit getGrape() {
return new Grape();
}
}
And in a ServletListener, I've set the active profile:
class MyServletListener implements ServletContextListener {
#Value("${app.fruit}")
private String fruitType;
public void contextInitialized(ServletContextEvent contextEvent) {
// Get Spring Context
WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(contextEvent
.getServletContext());
context.getAutowireCapableBeanFactory().autowireBean(this);
ConfigurableEnvironment configEnvironment = (ConfigurableEnvironment) context.getEnvironment();
logger.debug("0;Setting Active Profile: " + cacheRetrievalMode);
configEnvironment.setActiveProfiles(cacheRetrievalMode);
}
}
This is properly setting the active profile, which I can see. The only issue is, the listener is declared before the ContextLoaderListener, and by the time this is executed, the beans are already been created. Is there any alternative?
Will the instances stored in the map inside the factory be spring
managed bean?
Making the FruitFactory a managed bean
#Bean
public FruitFactory fruitFactory() {
return new FruitFactory();
}
doesn't make any of the objects it's referring to managed beans. However, this
#Bean
public Fruit getFruit() {
return fruitFactory().getFruit(fruitType);
}
does make that one returned Fruit a managed bean. #Bean marks a method as a bean definition and bean factory (it creates the bean). The object you return will be managed by Spring's bean life cycle.
Is there any issue with the implementation?
It seems weird that you're creating a FruitFactory bean but also a Fruit from that same FruitFactory. Are you even going to inject the FruitFactory elsewhere in the application?
I was trying to implement it in a better way, so that when a new fruit
comes, I don't have to modify my factory
Seriously, your factory is messing everything up. Spring already does its job, and more! Annotations make your life easier. You can give an identifier to the #Bean. You can qualify the bean with #Qualifier (and then also qualify the injection target with #Qualifier). You can set a #Profile for when and under which conditions the bean should be initialized.
But the issue is when and how the subclasses will be loaded? I'll not
be using the classes, not before putting their instances into the map.
Can anyone suggest a better way?
You can use bean initMethods, which you specify as a #Bean annotation attribute, or a #PostConstruct annotated method to do post-initialization logic. You can use these to register the beans with the factory, which you'll have injected (but that design doesn't sound right to me, you'd have to show us more.)
You should also look into InitializingBean and FactoryBean.
For setting the active profile, one possibility is to do the following. Create an ApplicationContextInitializer which sets the active profile by reading from a .properties file. You won't be able to use #PropertySources here because this isn't a bean.
Something like
public class ProfileContextInitializer implements
ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(ConfigurableApplicationContext applicationContext) {
PropertySource<Map<String, Object>> source = null;
try {
source = new ResourcePropertySource("spring.properties");
String profile = (String) source.getProperty("active.profile");
System.out.println(profile);
ConfigurableEnvironment env = applicationContext.getEnvironment();
env.setActiveProfiles(profile);
} catch (IOException e) {
e.printStackTrace();
}
}
}
You can register this in your deployment descriptor
<context-param>
<param-name>contextInitializerClasses</param-name>
<param-value>com.yourapp.ProfileContextInitializer</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
When the ContextLoaderListener is created, it will pick up and instantiate your class and call its initialize method. This is done before the WebApplicationContext is refreshed.
You should probably just set a VM argument for the active profile and avoid all of this.
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);
}