Maybe I am just blind, but I do not see how to use Guice (just starting with it) to replace the new call in this method:
public boolean myMethod(String anInputValue) {
Processor proc = new ProcessorImpl(anInputValue);
return proc.isEnabled();
}
For testing there might be a different implementation of the Processor, so I'd like to avoid the new call and in the course of that get rid of the dependency on the implementation.
If my class could just remember an instance of Processor I could inject it via the constructor, but as the Processors are designed to be immutable I need a new one every time.
How would I go about and achieve that with Guice (2.0) ?
There is some time since I used Guice now, but I remember something called "assisted injection". It allows you to define a factory method where some parameters are supplied and some are injected. Instead of injecting the Processor you inject a processor factory, that has a factory method that takes the anInputValue parameter.
I point you to the javadoc of the FactoryProvider. I believe it should be usable for you.
You can get the effect you want by injecting a "Provider", which can by asked at runtime to give you a Processor. Providers provide a way to defer the construction of an object until requested.
They're covered in the Guice Docs here and here.
The provider will look something like
public class ProcessorProvider implements Provider<Processor> {
public Processor get() {
// construct and return a Processor
}
}
Since Providers are constructed and injected by Guice, they can themselves have bits injected.
Your code will look something like
#Inject
public MyClass(ProcessorProvider processorProvider) {
this.processorProvider = processorProvider;
}
public boolean myMethod(String anInputValue) {
return processorProvider.get().isEnabled(anInputValue);
}
Does your Processor need access to anInputValue for its entire lifecycle? If not, could the value be passed in for the method call you're using, something like:
#Inject
public MyClass(Processor processor) {
this.processor = processor;
}
public boolean myMethod(String anInputValue) {
return processor.isEnabled(anInputValue);
}
Related
I have two classes with post construct initialization, and i need one of them to be injected based on a vm argument. I have done this kind of conditional injection in spring using #Conditional annotation, however i could not find any equivalent in CDI. Can some one please help me with this.
The code goes something like this,
public void impl1{
#PostConstruct
public void init(){
....
}
....
}
public void impl2{
#PostConstruct
public void init(){
...
}
....
}
If vmargument type=1, impl1 has to be injected and if type=2, impl2 has to be injected
For runtime decision (without changing your beans.xml), you basically have two options:
Option 1: use a producer method
#Produces
public MyInterface getImplementation() {
if(runtimeTestPointsTo1) return new Impl1();
else return new Impl2();
}
Drawback: you leave the world of bean creation by using new, therefore your Impl1 and Impl2 cannot #Inject dependencies. (Or you inject both variants in the producer bean and return one of them - but this means both types will be initialized.)
Option 2: use a CDI-extension
Basically listen to processAnotated() and veto everything you don't want. Excellent blog-entry here: http://nightspawn.com/rants/cdi-alternatives-at-runtime/
Probably the best way is to use an extension. You will create two classes both of which will have the same type so they are eligible for injection into the same injection point. Then, using the extension, you will disable one of them, leaving only one valid (the other will not become a bean).
Extensions can 'hook into' container lifecycle and affect it. You will want to leverage ProcessAnnotatedType<T> lifecycle phase (one of the first phases) to tell CDI that certain class should be #Vetoed. That means CDI will ignore it and not turn in into a bean.
Note the type parameter T in ProcessAnnotatedType<T> - replace it with a type of your implementation. Then the observer will only be notified once, when that class is picked up by CDI. Alternatively, you can replace T with some type both impls have in common (typically an interface) and the observer will be notified for both (you then need to add a login to determine which class was it notified for).
Here is a snippet using two observers. Each of them will be notified only once - when CDI picks up that given impl - and if it differes from the vm arg, it is vetoed:
public class MyExtension implements Extension {
public void observePAT(#Observes ProcessAnnotatedType<Impl1.class> pat){
// resolve your configuration option, you can alternatively place this login into no-args constructor and re-use
String vmArgumentType = loadVmArg();
// if the arg does not equal this impl, we do not want it
if (! vmArgumentType.equals(Impl1.class.getSimpleName())) {
pat.veto();
}
}
public void observePAT(#Observes ProcessAnnotatedType<Impl2.class> pat){
// resolve your configuration option, you can alternatively place this login into no-args constructor and re-use
String vmArgumentType = loadVmArg();
// if the arg does not equal this impl, we do not want it
if (! vmArgumentType.equals(Impl2.class.getSimpleName())) {
pat.veto();
}
}
}
Create your own #Qualifier and use it to inject cdi bean:
public class YourBean {
#Inject
#MyOwnQualifier
private BeanInterface myEJB;
}
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.FIELD, ElementType.METHOD})
public #interface MyOwnQualifier {
YourCondition condition();
}
I've been hacking with Google Guice a bit lately and I came up with an idea to inject a String to a constructor according to the class it is being declared in and other several parameters defined in an annotation. For example:
If I define a new qualifier annotation #NamedInjectable to be used by Guice:
#Documented
#Retention(RetentionPolicy.RUNTIME)
#Target({ ElementType.FIELD, ElementType.PARAMETER })
#Qualifier
public #interface NamedInjectable
{
String name() default "";
boolean indexed() default true;
}
Where name is a new name base for the string (default is only the class' name), and indexed states whether or not the name should be incremented each time a new string is being injected.
e.g.
public MyClass {
#Inject
public MyClass(#NamedInjectable(name = "foo", indexed = true) String name) {
// some code
}
}
And name param should be given a value such as "
I considered using Provider Bindings or AssistedInject but I could get it done. One main reason to failing, is somehow getting the name of the class.
Do you have any other idea?
There's no built-in way to customize a standard Guice binding based on names. If you want to stick to Guice alone, you'll probably need Custom Injections.
In addition to the standard #Inject-driven injections, Guice includes hooks for custom injections. This enables Guice to host other frameworks that have their own injection semantics or annotations. Most developers won't use custom injections directly; but they may see their use in extensions and third-party libraries. Each custom injection requires a type listener, an injection listener, and registration of each.
Guice's documentation example for Custom Injections demonstrates a logger instance customized with the type of the injecting class, which sounds very much like something you want to do—it's no more difficult to read the parameters of the annotation you create from within your TypeListener. However, this doesn't work directly with #Inject annotations or constructors, so you may have trouble if you're trying to make the injection happen entirely behind the scenes.
Another option is much simpler: Just use a factory and pass in the newly-constructed class.
public MyClass {
private final String name;
#Inject
public MyClass(NameInjector nameInjector) {
this.name = nameInjector.get(this, "foo", true);
}
}
For ordinary Guice injections, you can't access the name of the class where the something is being injected. If you really need to do that, you would need to use custom injection.
By using a custom TypeListener, you can listen for injection events and know the class that is being injected. On hearing an injection event, you can register a custom MembersInjector that Guice will invoke after it finishes its own injections. This MembersInjector has access to the fully-constructed instance of the class, so it can reflect on fields and inspect annotations. However, it obviously can't inject constructor parameters, since the object has already been created.
In short, there is no way to do custom injection of constructor parameters. But the idea you describe is very possible for field injection!
How to do it
First, you need to register a TypeListener (this code based on the linked Guice wiki page):
public class NamedStringListener implements TypeListener {
public <T> void hear(TypeLiteral<T> typeLiteral, TypeEncounter<T> typeEncounter) {
Class<?> clazz = typeLiteral.getRawType();
while (clazz != null) {
for (Field field : clazz.getDeclaredFields()) {
if (field.getType() == String.class &&
field.isAnnotationPresent(NamedInjectable.class)) {
Annotation annotation = field.getAnnotation(NamedInjectable.class);
// How you create and configure this provider is up to you.
Provider<String> provider = new MyStringProvider(clazz, annotation);
typeEncounter.register(new MyMembersInjector<T>(field, provider));
}
}
clazz = clazz.getSuperclass();
}
}
}
Then, inside MyMembersInjector<T>:
public class MyMembersInjector<T> implements MembersInjector<T> {
final Field field;
final Provider<String> provider;
NamedMembersInjector(Provider<String> provider) {
this.field = field;
this.provider = provider;
this.field.setAccessible(true);
}
public void injectMembers(T t) {
field.set(t, provider.get());
}
}
I leave the implementation of MyStringProvider up to you.
See the Guice CustomInjections wiki page for more.
I have used the standard factory pattern method before to create instances of classes (implementing a specific interface) using a Factory class, which has a "create" method, that returns the right instance based on the parameter passed to it (example snippet given below):
public class SimpleFactory {
public static SimpleObjectInterface getSimpleObject(int data) {
SimpleObjectInterface toReturn;
switch(data) {
case 1:
toReturn = new OneSimpleObject();
break;
case 2:
toReturn = new TwoSimpleObject();
break;
default:
toReturn = new DefaultSimpleObject();
break;
}
return toReturn;
}
}
Now I am using Guice in my project for dependency injection. My question is how can I achieve something like the above using Guice? Which implementation instance is needed is decided at runtime based on some user input.
I have looked at Provider and #Named annotations. But I don't understand how exactly it will help me.
In general for the problem where you want a factory that injects most dependencies, but still allows some client-supplied deps, you would use Factories by Assisted Injection.
However in your case this would lead to conditional logic in your factory, which is probably not ideal (it is explicitly discouraged in Guice modules).
I think for your situation a MapBinder would be ideal, and you wouldn't need a factory at all, since you're only switching on data type and not building anything really. In your module you configure a map of int (in your case) keys to impls of SimpleObjectInterface. Then in your main runtime class you inject the map, and when you need an instance of a simple object and have int data available, you call get(data) on the injected map.
I don't have an IDE on this machine, so I can't test the code, but from memory it would be something like below:
In your module:
public class MyModule extends AbstractModule {
protected void configure() {
MapBinder<Integer, SimpleObjectInterface> mapbinder
= MapBinder.newMapBinder(binder(), Integer.class, SimpleObjectInterface.class);
mapbinder.addBinding(1).toClass(OneSimpleObject.class);
mapbinder.addBinding(2).toClass(TwoSimpleObject.class);
}
}
In your app code:
#Inject
private Map<Integer, SimpleObjectInterface> simpleObjectMap;
...
void applicationCode() {
...
Integer data = getData();
SimpleObjectInterface simpleObject = simpleObjectMap.get(data);
...
}
Only issue here is you can't have the "default" binding that you had in your switch statement. Not sure of the best way to handle that, maybe you could assign a default impl in your app code if the object is still null after trying to instantiate it from the map binder. Or you could go back to assisted inject with conditional logic, but it's not really "assisted" injection if the sole dependency is client supplied.
See also: Can Guice automatically create instances of different classes based on a parameter?
I am working on a project where I am using MyBatis annotations as persistence framework. Therefore, I have to create an interface for the 'mapper' and compose the mapper in the service like :
class XYZServiceImpl{
public XYZMapper getXYZMapper(){
return SessionUtil.getSqlSession().getMapper(XYZMapper.class)
}
}
Now while unit testing the service with Mockito, I am trying to inject a mock for the mapper. But since I am injecting mock in an instance of XYZService, how can mock a method of the service itself, in this case getXYZMapper() is what I am trying to stub. Although I have got a solution of creating the instance XYZMapper in the service and not call on demand like the above code does something like :
Class XYZServiceImpl{
XYZMapper mapper;
public void useXYZMapper(){
mapper = SessionUtil.getSqlSession().getMapper(XYZMapper.class);
}
}
But that would bring a lot of code changes (ofcourse I can refactor) but is there a way to achieve without having to make code changes?
Also what would be a 'purist' way to have a mapper instance in the class is it the method 1 that is better than method 2 in terms of performance?
EDIT : Here XYZMapper is an interface. Something like :
public interface XYZMapper{
#Select("SELECT * FROM someclass WHERE id = #{id}")
public SomeClass getSomeClass(int id);
}
EDIT : I am facing a similar situation but with a variance that I have a service that I do want to test like XYZServiceImpl. Now it has a method getXYZDetails() which has a lot of business logic handled within the service. Now if getXYZDetails looks like the following :
public XYZDetails getXYZDetails(int id){
XYZDetails details = new XYZDetails();
details.set1Details(fetchSet1Details(id));
//Perform some business logic
details.set2Details(fetchSet2Details(id));
if(details.set2Details() != null){
for(int i = 0; i < details.set2Details().size(); i++){
flushTheseDetails(i);
}
}
.
.
}
Kindly notice that fetchSet1Details(), fetchSet2Details(), flushTheseDetails are public service, public and private service respectively.
I want to know of a method that can mock/stub these methods while testing getXYZDetails() thus enabling me to
There are several options you can use.
Inject dependency
This works only for simple methods like getXYZMapper when method only returns external dependency of you object. This may require to create new XYZServiceImpl instances if for example mapper is bound to connection which is opened per request.
Encapsulate method behavior in object
Another way to achieve similar result is to use a factory or service locator
like this:
public class XYZServiceImpl {
public XYZServiceImpl(XYZMapperFactory mapperFactory) {
this.mapperFactory = mapperFactory;
}
public XYZMapper getXYZMapper() {
return mapperFactory.getMapper();
}
}
This will allow you easily substitute factory in test with implementation which returns mock mapper.
The similar approach can be used for other methods fetchSet1Details, fetchSet2Details, flushTheseDetails that is moving them to other class or classes. If the method contains complex (and may be loosely related) logic it is a good candidate to be moved in separate class. Think about what these methods do. Usually you can move some essential and unrelated part of them to other class or classes and this makes mocking them much easier.
Subclass
This is not recommended but in legacy code sometimes is very helpful as a temporary solution.
In your test subclass you class under test and override methods you need:
#Test
public void someTest() {
XYZServiceImpl sut = new XYZServiceImpl() {
public XYZMapper getXYZMapper() {
return mapperMock;
}
public Whatever fetchSet1Details() {
return whateverYouNeedInTest;
}
}
sut.invokeMethodUnderTest();
}
The only thing you may need to do is to change access modifier of private method to package-private or protected so you can override them.
Spying
This method in also discouraged but you can use mockito spies:
XYZServiceImpl realService = new XYZServiceImpl();
XYZServiceImpl spy = Mockito.spy(realService);
when(spy.fetchSet1Details()).thenReturn(whaeveryouneed);
when(spy.getXYZMapper()).thenReturn(mockMapper);
spy.methodUnderTest();
I would suggest the "purist" way of doing this is to accept an XYZMapper instance in your constructor and store it in a local field.
In production use, you can pass an e.g. SQLXYZMapper, which will interact with your database. In test use, you can pass in a mocked object that you can verify interactions with.
I'm reviewing Guice. Let's say I've got the following setup:
public interface IsEmailer {...}
public interface IsSpellChecker {...}
public class Emailer implements IsEmailer {
#Inject
public class Emailer(final IsSpellChecker spellChecker)....
}
public class FrenchSpellChecker implements IsSpellChecker {....}
public class EnglishSpellChecker implements IsSpellChecker {....}
#BindingAnnotation public #interface English {}
#BindingAnnotation public #interface French {}
Then in my module I've bound the interfaces to their respective implementations, and annotated the spell checkers with the respective binding-annotation.
Now, let's say based on a runtime variable I need to construct an emailer that either uses the English or the French spell checker.
I thought of using a named providers in my module:
#Provides
#English
IsEmailer provideEnglishEmailer() {
return new Emailer(new EnglishSpellChecker());
}
#Provides
#French
IsEmailer provideFrenchEmailer() {
return new Emailer(new FrenchSpellChecker());
}
This works like this:
IsEmailer emailer = myModule.getInstance(Key.get(IsEmailer.class,
French.class));
Is this the cleanest way to do something like this? After all, I'm forced to construct the object by hand (in the providers).
Thanks
First some notes:
Generally you want to avoid using getInstance as much as possible, except for your "root" element (e.g. YourApplication). Within anything that Guice provides, your best bet is to ask for an injection of Provider<IsEmailer>, or perhaps #English Provider<IsEmailer> and #French Provider<IsEmailer>. Guice will not actually create the elements until you call get on the Provider, so the overhead of creating the Provider is very very light.
You don't have to bind to a provider to get a provider. Guice will resolve any binding of X, Provider<X>, or #Provides X to any injection of X or Provider<X> automatically and transparently.
Provider implementations can take injected parameters, as can #Provides methods.
If you want to bind a lot of things to #English or #French, you may also investigate private modules, since this sounds like the "robot legs" problem to me.
The easiest way is simply to go with the first bullet and inject a Provider of each, especially if you're only doing this once.
You can also bind it in a Module, if your runtime variable is accessible via Guice. Put this in your module along with the #Provides annotations above. (As noted, you may want to rewrite them to accept an EnglishSpellChecker and FrenchSpellChecker as parameters respectively, to enable the spell checkers to inject their own dependencies.)
#Provides IsEmailer provideEmailer(Settings settings,
#English Provider<IsEmailer> englishEmailer,
#French Provider<IsEmailer> frenchEmailer) {
if (settings.isEnglish()) {
return englishEmailer.get();
} else {
return frenchEmailer.get();
}
}
You could use a MapBinder. That would allow you to inject a Map<Language, IsSpellChecker>, and then retrieve the appropriate spell checker at runtime.