Consider a simple bean:
#Component
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class A {
public A(Integer a){}
public A(String a){}
}
Having an instance of BeanFactory I can create A instances with:
beanFactory.getBean(A.class, 1); // using A(Integer)
beanFactory.getBean(A.class, "1"); // using A(String)
Now, I want to have a subclass of A that uses one of the two constructors provided. My class hierarchy now becomes:
#Component
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
#Primary
public class A {
public A(Integer a) {}
public A(String a) {}
}
#Component
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class A1 extends A {
public A1() { super(1); }
}
I would expect these to work now:
beanFactory.getBean(A.class, 1); // using A(Integer)
beanFactory.getBean(A.class, "1"); // using A(String)
beanFactory.getBean(A1.class); // using the A1()
However, first two calls fail with
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'A1' defined in file [...]: Could not resolve matching constructor
(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)
Please note that I'm not trying to create subclass with some argument like author of this question.
Also note that if I define (useless) A1(Integer) and A1(String) constructors, Spring does not complain anymore.
Using Spring 4.2.2.RELEASE.
Why bean factory can not create base class instances with its constructors when I define some child?
Please find an unit test reproducing it in Github repo.
Reason for this behavior is this : Spring don't use constructor args to determine the appropriate bean type to instanciate. (or, in other words: it only use constructor args to resolve the correct constructor to use)
Let's consider only this line beanFactory.getBean(A.class, 1);
The bean resolution is the following :
determine all beans with the requested type. In your case : there are 2 possible beans : A or A1 (both are of type A)
create one instance of every possible type found at step 1 and to do it use the most appropriate constructor according given args. In your case instantiate one A and one A1 using a constructor with an Integer. (side note: we are talking about prototype beans here. For singleton beans : a new instance is created if and only if it don't already exists)
look for a #Primary in all instantiated bean at step 2 (if found return it)
look for bean with highest priority in all instantiated bean at step 2 (if found return it)
throw a "no unique bean exception"
In your case : the algorithm fail at step 2 when trying to instantiate a bean of type A1 with one Integer argument.
When you define A1(String) and A1(Integer) : the algorithm don't fail at step 2 and so goes to step 3 and resolve the type because of the #Primary on class A.
Source code is here. Take a close look at line 353 --> 366 for the algorithm described here.
I can only guess the reason for such behavior, but it maybe because you can specify default values for constructor args and therefore: constructor args (passed to getBean(Class, args...) ) aren't a valid clue to disambiguate bean type.
Related
I have 3 beans which implements same interface. But i want to instantiate only one of them, if A is available then A, if there is no A then B, and if there is no A and B then C.
When i had only two of them it was simple, default one had '#ConditionalOnMissingBean' annotation. But not sure will that work with 3 of them.
Is it possible to solve this with annotations?
I don't want to create factory method, as I have multiple applications using those components, and i dont have ability to change some of them
Yes, using the #ConditionalOnMissingBean annotation , you should set the code like this:
#Configuration
public class ConditionalOnMissingBeanConfig {
#Bean
public A beanA(){
return new A(); // will initialize as normal
}
#Bean
#ConditionalOnMissingBean(name="beanA")
public B beanB(){
return new B(); // it will not initialize as
// beanA is present in the beanFactory.
}
#Bean
#ConditionalOnMissingBean(name="beanB")
public C beanC(){
return new C(); // will get initialized as there is no
// bean with name beanB in BeanFactory.
}
}
Conditional that only matches when the specified bean is missing from the beanfactory. This will only match when the bean definition is processed by the application context and as such is recommended to be used by auto-configuration classes only.
Let me propose an alternative approach:
You can introduce a configuration variable that will denote the "domain" related explanation of what should the system do
Example:
If A, B, C are, say, different caching strategies (in-memory, redis, ehcache), then introduce the following configuration value:
caching.type=ehcache // or in-memory or redis
Then the beans can be declared as follows:
#ConditionalOnProperty(name="caching.type" , havingValue="in-memory", matchIfMissing = true) // this is a fallback if no property is specified
class InMemoryCaching implements CachingStrategy {}
#ConditionalOnProperty(name="caching.type" , havingValue="ehcache", matchIfMissing = false)
class EhcacheCaching implements CachingStrategy {}
#ConditionalOnProperty(name="caching.type" , havingValue="redis", matchIfMissing = false)
class RedisCaching implements CachingStrategy {}
I know its slightly different solution, but it has the following benefits:
its easy to add yet another implementation of the interface - no code changes in existing beans
beans are not aware of each other even not at the level of bean names in spring
easy to debug - just look at the configuration property value
this approach can be applied to #Configuration and manage set of beans
Why my code is failing with the below error when I AUTOWIRE the no arg constructor but it runs fine when I autowire only the single arg constructor
Exception in thread "main" java.lang.NullPointerException
Here is TennisCoach Class code snippet
#Component // this is bean id
public class TennisCoach implements Coach {
public TennisCoach(FortuneService thefortuneservice) {
System.out.println(" inside 1 arg constructter");
fortuneservice = thefortuneservice;
}
#Autowired
public TennisCoach() {
System.out.println(" inside 0 arg constructter");
}
}
Coach theCoach = myapp.getBean("tennisCoach", Coach.class);
System.out.println(theCoach.getDailyFortunes());
How are things working behind the scene?
If you have only one constructor in a class, you don't need to use #Autowired--Spring understands that there's only one option, so it uses that one. But you have two constructors, so you need to tell Spring which one to use.
When you invoke the default constructor, however, what do you expect to happen? You don't set up your variables anywhere at all, but you are trying to read from them.
Constructor with no arguments doesn't want you put #Autowired on it as you are not injecting anything in its arguments (since there are none). #Autowired is required for constructor with arguments however.
#Component annotation above the class will create your bean via calling the default constructor and you can use that anywhere but need to make sure that you don't call anything on the fortuneservice as that will result in a null ptr exception unless you initialize it. On the contrary, if you put #Autowired annotation on top of constructor with argument and it runs fine then that means that the fortuneservice bean that you have declared elsewhere will now be injected inside this class and no null ptr exception if you call some method on that.
Adding to the previous to answers - think about the term "constructor injection". You are INJECTING references via constructor parameters. When you #Autowire an empty constructor, there isn't anything to inject. Therefore you get a NullPointerException when attempting to access the field that was supposed to have a reference injected into.
I need to dynamically Inject a variable group of classes in my application. The purpose is, as the application grows, only have to add more classes inheriting the same interface. This is easy to do with tradicional java as I just need to search for all classes in a package and perform a loop to instantiate them. I want to do it in CDI. For example:
public MyValidatorInterface {
public boolean validate();
}
#Named
MyValidator1 implements MyValidatorInterface
...
#Named
MyValidator2 implements MyValidatorInterface
...
Now the ugly non real java code just to get the idea of what I want to do:
public MyValidatorFactory {
for (String className: classNames) {
#Inject
MyValidatorInterface<className> myValidatorInstance;
myValidatorInstance.validate();
}
}
I want to loop over all implementations found in classNames list (all will be in the same package BTW) and Inject them dynamically so if next week I add a new validator, MyValidator3, I just have to code the new class and add it to the project. The loop in MyValidatorFactory will find it, inject it and execute the validate() method on the new class too.
I have read about dynamic injection but I can't find a way to loop over a group of class names and inject them just like I used to Instantiate them the old way.
Thanks
What you are describing is what Instance<T> does.
For your sample above, you would do:
`#Inject Instance<MyValidatorInterface> allInstances`
Now, allInstances variable contains all your beans which have the given Type (MyValidatorInterface). You can further narrow down the set by calling select(..) based on qualifiers and/or class of bean. This will again return an Instance but with only a subset of previously fitting beans. Finally, you call get() which retrieves the bean instance for you.
NOTE: if you call get() straight away (without select) in the above case, you will get an exception because you have two beans of given type and CDI cannot determine which one should be used. This is implied by rules of type-safe resolution.
What you most likely want to know is that Instance<T> also implements Iterable so that's how you get to iterate over the beans. You will want to do something like this:
#Inject
Instance<MyValidatorInterface> allInstances;
public void validateAll() {
Iterator<MyValidatorInterface> iterator = allInstances.iterator();
while (iterator.hasNext()) {
iterator.next().callYourValidationMethod();
}}
}
I followed the following example of dependency injection: http://www.tutorialspoint.com/spring/spring_autowired_annotation.htm
For example the TextEditor class (from the above link):
public class TextEditor {
private SpellChecker spellChecker;
#Autowired
public void setSpellChecker( SpellChecker spellChecker ){
this.spellChecker = spellChecker;
}
public SpellChecker getSpellChecker( ) {
return spellChecker;
}
public void spellCheck() {
spellChecker.checkSpelling();
}
}
How can these dependencies/classes be instantiated, while they don't have any constructor?
Is Java simply making an object of that type, that is empty? Like an empty parameter constructor without any code?
Thanks for making this more clear!
Unless specified otherwise, every Java class has the default constructor. So here, you have a default public TextEditor() constructor, even though you haven't coded for it. (You could code it if you needed to change its visibility from public, declare a thrown exception, etc.)
So yes, Spring calls this default constructor - then calls the setSpellChecker method (as annotated, and through reflection) to populate it.
If no constructor is defined, a class can be instantiated via the no-argument default constructor.
So, the framework calls that constructor (supposedly using reflection) and then uses the set method to set the one field of the freshly created class.
The example above is using Spring annotations and Spring context file and those are the main and most important parts of the project, considering the DI.
So in the context file you have following line:
<!-- Definition for spellChecker bean -->
<bean id="spellChecker" class="com.tutorialspoint.SpellChecker">
</bean>
this defines a class with reference spellChecker that mapps to a class com.tutorialspoint.SpellChecker and once the compiler find such property in a method that is marked as #Autowired on instantiation of the object it injects/sets the relevant version of the required dependency.
In cases where a property doesn't match a reference tag in the applicationContext.xml file Spring is trying to map the type e.g. property with name mySpecialSpellChecker which has type of com.tutorialspoint.SpellChecker still will be mapped to bean with id="spellChecker" if there are more than one of same type Spring won't instantiate your object and you might get compile time error as Spring can't know which version of the two (or more) is the correct one so this requires developer input.
This is the order of execution:
instantiate textEditor, this has default constructor that is not visible in the code public TextEditor ()
the new instance is set in a pool of available objects with reference textEditor
instantiate spellChecker and add to the pool of available object with relevant reference/label
all #Autowired properties/methods are set/called with relevant objects in this case Spring calls: setSpellChecker(spellChecker)
I have the following code:
public IFoo getFoo(Type type) // Type is an enum containing A, B etc.
{
switch(type)
{
case A: return new Foo1(); // implements IFoo
case B: return new Foo2(); // implements IFoo
etc.
}
}
This obviously violates OCP, so I need to refactor; plus I now need to return prototype beans which are managed by a Spring container. To achieve this, I can think of the following options:
1) make this class AppContextAware; create a Map<Type, String> where String is the bean id; define these beans as prototype in Spring Config and define this Map too in Spring config and get it injected in this class, then get the bean id from this map for a given enum and use it to get a bean from AppContext,
2) similar approach, but for the value in Map, use a TargetSource which has an abstract method which I call in getTarget() and I wire the defined prototype beans using lookup-method as this abstract method per TargetSource definition,
3) similar approach, but I use a FactoryBean instead of TargetSource.
In #1 my class depends on AppContext, in other approaches it doesn't. So I'm leaning towards #2 or #3, but which one to pick? Or is there any other, better approach that I haven't thought of?
I ended up using #1 anyway, as it's the simplest, and creates lesser number of beans.
Take a look at The FactoryBean, migth be the thing you are looking for. Take a look at here for an example.
hth