I am using guice for dependency injection in my project. I have a few interfaces for which I have default bindings.
I want to provide the facility where the user can implement the interface and that custom implementation would be binded over default one. If no custom implementation is present Default binding should happen.
How can this be done?
I thought of a way where the user annotates the implemented classes with an annotation and I can get the interface from that and bind that class to that interface. Is this possible?
Please help.
Thank you.
when you use spring framework, you can use declare a bean with #ConditionalOnMissingBean, if not, you can try to implement like this(check whether the object has bean declared)
Probably best would be to have a BeanFactory, and the user should then provide his implementation for a given interface:
class BeanFactory {
private static final Map<Class<?>, ?> beans = new HashMap<>();
public static <T> void register(Class<T> type, T impl){
beans.put(type, impl);
}
}
That way you could have your beans initially declared in above factory and then they could get overwritten by a user.
class MyImpl implements MyService{
static{
BeanFactory.register(MyService.class, new MyImpl());
}
// Rest of code
}
also, you can use SPI
ServiceLoader<SayHello> services = ServiceLoader.load(SayHello.class);
if services is empty, you can new the default instance.
Related
I'm trying to understand how to handle conditionally creating new instances of a class that uses #Inject. In the below example I have a factory that instantiates classes based on a parameter.
AnimalFactory does not have access to the injector the main class of my application has, so I can't use injector.getInstance(Cat.class)
class AnimalFactory {
public IAnimal create(AnimalType type) {
if (type.equals(AnimalType.CAT)) {
return new Cat(); // Cat uses #Inject, so this won't work of course. But ???
} else if (type.equals(AnimalType.DOG)) {
return new Dog();
}
}
}
In the rest of my app, classes are injected into my constructors because I always need them. Guice creates an instance/singleton for each. But in this scenario, I do not want to create and inject instances for each animal because all but one are needed.
You can use a MapBinder as described here:
public class AnimalModule extends AbstractModule {
public void configure() {
MapBinder<AnimalType, IAnimal> animalBinder= MapBinder.newMapBinder(binder(), AnimalType.class, IAnimal.class);
animalBinder.addBinding(AnimalType.DOG).to(Dog.class);
...
}
}
And than use it in your factory:
class AnimalFactory {
#Inject
Map<AnimalType, IAnimal> animals;
public IAnimal create(AnimalType type) {
return animals.get(type);
}
}
Actually I worked on exactly the same issue and I wrote a feature that allows you to create self-populating factory. Meaning that if you work in Spring/Spring-boot environment you can create a factory that can access and provide any interface implementing class that is managed by Spring-boot without injecting in the factory. You can also give the instances custom names. So, it seems like it fits your case exactly. Here is a link to an article that describes the feature in great detail: Non-intrusive access to "Orphaned" Beans in Spring framework. Also, in MgntUtils library Javadoc there is a good description of the feature here enter link description here. The library itself including source code could be found on Github here and in the package com.mgnt.lifecycle.management.example there is a working example. Maven artifacts are here
I have a Spring based Java application where a lot of classes use the following autowired interface.. they work off this interface at all places.
#Autowired
private IOperatingSystemManager m_operatingSystemManager;
Right now, there is only one implementation of the interface as follows:
#Component
public class WindowsManager implements IOperatingSystemManager
{
// Windows based shenanigans
}
And the application works as expected. Spring is happy. Everybody is happy.
Alright, not everybody...
So, I want to add another concrete implementation of IOperatingSystemManager ..
#Component
public class LinuxManager implements IOperatingSystemManager
{
// Linux based shenanigans
}
What we want is the auto wiring of IOperatingSystemManager conditionally based on a properties file setting. (say.. os=windows.. basically something that is an arbitrary string and cannot be derived from system properties etc. simply because this is a dummy example. the actual managers are not OS related.)
I don't want to change any of the classes who have autowired to the interface and are working off the interface. All I need is for Spring to look at some logic that will dictate the Autowiring of the variables and wire up the right concrete instance for:
#Autowired
IOperatingSystemManager m_operatingSystemManager
at all the gazillion places.
The documentation & web search talk about profiles, condition, bean factory, qualifiers etc.. but we don't want to use Profiles; and Qualifiers seem to be needing changes to all the interface variable annotations.
Factory methods look promising, but being new to Spring, couldn't find a crisp answer.
What is a simple and recommended way to achieve this?
Instead of scanning the WindowsManager class, create one concrete instance that implements the IOperatingSystemManager interface or another one, depending on the your logical conditions.
First, remove the #Component annotation from the WindowsManager class.
Then, create and scan this #Configuration class, which will act as a factory for your beans:
#Configuration
public class OperatingSystemManagerFactory {
#Bean
public IOperatingSystemManager getOperatingSystemManager() {
if ( /* some logic that evaluates to true if windows */ ) {
return new WindowsManager();
} else {
// Linux default option ;)
return new LinuxManager();
}
}
}
With this solution, you shouldn't need to update anyone of your classes that reference the IOperatingSystemManager interface.
I dont know which version of spring you are using but you have options for this
http://www.intertech.com/Blog/spring-4-conditional-bean-configuration/
Here, as you can see, you can create a bean based on a condition that you can decide. It actully gave your example, Windows and Linux :), so i believe thats what you are looking for.
Edit:
If you are using spring-boot, you have some other Conditional annotations
http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-auto-configuration.html#boot-features-condition-annotations
I have an Interface and multiple implementation classes, around 10, of this interface.
I have a naming convention like prefix + name + suffix so during runtime, I can add
#Autowired
private Map<String, MyInterface> myImplementations;
and then access the implementation class with myImplementations.get() method.
Is there a better way of accessing those implementations? I only know which impl. I needed during runtime, changes depends on the message I received.
You can implement BeanFactoryAware interface in your class and then use injected bean factory to get needed implementation:
Interface impl = beanFactory.getBean("interfaceimpl");
or
Interface impl = beanFactory.getBean(InterfaceImpl.class);
In spring when I do:
#Autowire
List<MyInterface> myInterfaces;
then this list will get populated by all beans which implement MyInterface. I didn't have to create bean of type List<MyInterface>.
I'm looking for such behaviour in Google Guice.
Sofar I went with:
Multibinder<MyInterface> myInterfaceBinder = MultiBinder.newSetBinder(binder(), MyInterface.class);
Now if I have a bean which implements MyInterface and I bind it, say via:
bind(MyInterfaceImpl.class).asEagerSingleton();
it won't be included in my multibinder. I need to add:
myInterfaceBinder.addBinding.to(MyInterfaceImpl.class);
This is somewhat more complicated than what Spring offers. So I was wonmdering whether I'm not using it in wrong way. So is there easier way of achieving this?
I haven't used it that way myself, yet, but according to Guice's API documentation, I think you should be able to write something not much more than this once:
bindListener(Matchers.subclassesOf(MyInterface.class), new TypeListener() {
public <I> void hear(TypeLiteral<I> typeLiteral,
TypeEncounter<I> typeEncounter) {
myInterfaceBinder.addBinding().to(typeLiteral);
}
}
Then, when you bind an implementation via
bind(MyInterfaceImpl.class).asEagerSingleton();
it should be added to your multibinder automatically.
A hacky solution would be to do it all in a loop:
Multibinder<MyInterface> myInterfaceBinder
= MultiBinder.newSetBinder(binder(), MyInterface.class);
Class<? extends MyInterface>[] classes = {
MyInterfaceImpl,
YourInterfaceImpl.class,
MyCatsInterfaceImpl
};
for (Class<? extends MyInterface> c : classes) {
bind(c).asEagerSingleton();
myInterfaceBinder.addBinding.to(c);
}
It's hacky, it's applicable for such simple cases only, but it's simple and DRY.
In all of the Guice examples I have found, getting an instance involves calling Injector.getInstance() with the concrete class as a parameter. Is there a way to get an instance from Guice using only the interface?
public interface Interface {}
public class Concrete implements Interface {}
Interface instance = injector.getInstance(Interface.class);
Thanks
Actually that's exactly what Guice is made for.
In order to make getInstance() work with an interface you'll need to first bind an implementation of that interface in your module.
So you'll need a class that looks something like this:
public class MyGuiceModule extends AbstractModule {
#Override
protected void configure() {
bind(Interface.class).to(Concrete.class);
}
}
Then when you create your injector you just need to pass an instance of your module in:
Injector injector = Guice.createInjector(new MyGuiceModule());
Now your call to injector.getInstance(Interface.class) should return a new instance of Concrete using the default constructor.
Of course there are many many more ways you can do bindings but this is probably the most straight forward.
It works for interface as well:
bind( Interface.class ).to( Concrete.class );
Without using a Module, you can also specify the implementation class to be used by default, directly in the interface declaration:
#ImplementedBy(Concrete.class)
public interface Interface {}
This doesn't necessarily fit every situation but I found this comes in handy most of the times.
Additionnally, when using #ImplementedBy annotation, you can still override the implementation class by binding another concrete class in a Module. That can also be useful.