Constructor arguments in autowiring sources - java

What exactly causes this?
org.springframework.beans.factory.NoSuchBeanDefinitionException: \
No unique bean of type [fi.utu.keycard.business.KeyCardManager] \
is defined: expected single matching bean but found 2: \
[dataBaseTarget, database]
// etc. (rest of Stack Trace is irrelevant)
What I need is autowiring 3 things: validator, ldap connection and database connection.
I call it:
#Controller
Controller(KeyCardManager database,
LdapPersonDao personManager,
GiveFormValidator validator)
The error seems to cause by another bean, if I change the order of these parameters. I have no signing-in, so I dont have UserDetails or so.

The fix is probably something like this:
public Controller(
#Qualifier("beanQualifier") KeyCardManager database,
LdapPersonDao personManager,
GiveFormValidator validator
)
Since there are apparently two beans of type KeyCardManager in your application context, you need to tell the context which one to wire.
Unfortunately the #Qualifier mechanism doesn't work with bean names, you must either annotate the actual bean with a corresponding #Qualifier or add a <qualifier> element to the XML bean definition.
The #Resource annotation works with bean names, but it doesn't support Constructor parameters (that's not Spring's fault, it's a JSR-250 standard annotation with #Target({TYPE, FIELD, METHOD}))
Reference:
Autowiring Collaborators
Fine-tuning annotation-based
autowiring with qualifiers
Troubleshooting
If you don't know why there are two beans of the same type in the context, first of all navigate to the bean interface (I assume KeyCardManager is an interface, if not, do the same thing for the class anyway) and if you use Eclipse select Navigate > Open Type Hierarchy. If you find more than one concrete class that inherits from KeyCardManager (including KeyCardManager itself), then there's probably your problem.
If that is not the case, you probably have two beans of the same type in your application context. One way that can happen is when you define a bean through both XML and classpath scanning. I.e. if you have this line in your XML:
<context:component-scan base-package="org.example"/>
Make sure you don't manually wire any beans from the org.example package (or you will have double beans, which can lead to the problem you have).

org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [fi.utu.keycard.business.KeyCardManager] is defined: expected single matching bean but found 2: [dataBaseTarget, database]
It seems you are autowiring by class type. but there are multiple bean available in the context with same class. which are dataBase & dataBaseTarget
byType
Allows a property to be autowired if
there is exactly one bean of the
property type in the container. If
there is more than one, a fatal
exception is thrown, and this
indicates that you may not use byType
autowiring for that bean. If there are
no matching beans, nothing happens;
the property is not set. If this is
not desirable, setting the
dependency-check="objects" attribute
value specifies that an error should
be thrown in this case.
Document

Related

ConditionalOnMissingBean by name

I have multiple datasource beans defined in my configuration file.I have 2 beans named customerDataSource. I want one of them to be instantiated only if other bean is not loaded.I was trying to use #ConditionalOnMissingBean. However it looks like this will work only when another bean of same "type" is not present. Is there a way to control this by using "name"?
The annotation has the parameter name, where you can specify the bean name that should be checked:
#ConditionalOnMissingBean(name = "beanNameToCheck")

Enforce initialization of Spring Bean which's reference is not explicitly used

Is there a way to enforce the initialization of a Spring Bean in cases that the reference of the bean is never explicitly used or even requested in the ApplicationContext?
<bean class="foo.bar.FooBar>
<property name="fooBar" ref="foo.bar.reference"/>
</bean>
This bean is meant to do things inside, get's properties passed by IoC but it is never used by any other bean which implies that the it's reference is nowhere else configured.
My problem is, that this bean seems not to be initialized because of that.
I tried <bean .. lazy-init="false"/> but this did not do the trick.
How can ensure the bean is going to be initialized?
Since I cannot modify the application context, I would need a way doing it just in the XML configuration.
I'm not sure, but maybe you could try to use the singleton=true property for that bean - in non-singleton mode, the bean would be instatiated only if requested by the application.
http://docs.spring.io/spring/docs/1.2.9/reference/beans.html
(see 3.2.5)
Edit: Can you add some logging to ctor to see if it's called? If not, could you add an init-method and log something there?

systemProperties and integrationGlobalProperties conflict

So i have a situation when I need to use spring integration. So I create application context for it and then i describe my all logic in it. But now, I have an error something like this:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [java.util.Properties] is defined: expected single matching bean but found 2: [integrationGlobalProperties, systemProperties]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:800)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:707)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByType(AbstractAutowireCapableBeanFactory.java:1184)
... 61 more
Does someone faced with this problem with systemProperties and integrationGlobalProperties? What does it mean?
P.s. my application context is imported into another application context which has "default-autowire="byType"
As you see your context has two bean of java.util.Properties. That means that you can't inject byType.
Use #Qualifier("systemProperties") to restrict it to specific Properties.
The integrationGlobalProperties isn't only one bean which is populated by Framework. And it isn't a surprise that autowire byType is more and more bad for real applications.
I recently faced same issue. After some research I have decided to wirte a CustomBeanPostProcessor class (implementing BeanFactoryPostProcessor) which will try to find conflicting bean and change its 'autowire' property to 'byName', thus avoiding conflict.
Please have a look at a code below:
public class CustomBeanPostProcessor implements BeanFactoryPostProcessor{
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
if (beanFactory.containsBean("integrationGlobalProperties")){
//Choose on of the options - either disable autowiring for bean completly,
//or change autowiring type
beanFactory.getBeanDefinition("integrationGlobalProperties").setAutowireCandidate(false);
beanFactory.getBeanDefinition("integrationGlobalProperties").setAttribute("autowire", "byName");
}
}
}
Do not forget to declare this class as Spring bean as well:
<bean class="edu.stackoverflow.spring.misc.CustomBeanPostProcessor"/>

Spring set abstract bean property value

I need to chance spring bean property values on runtime. Currently I'm doing it this way
Object bean = context.getBean(beanName);
BeanWrapper wrapper = PropertyAccessorFactory.forBeanPropertyAccess(bean);
wrapper.setPropertyValue(propertyName, newValue);
But some beans are configured as abstract
<bean id="abstractFoo" abstract="true" class="com.Foo" />
<bean id="bar" class="com.Bar">
<constructor-arg><bean parent="abstractFoo" /></constructor-arg>
</bean>
and in that case context.getBean("abstractFoo") throws BeanIsAbstractException
This is really simplified example, but I hope you get the idea.
Any idea how to change property value of abstract bean (in this case 'abstractFoo')?
We're using spring 2.5.4
Edit
Changed a XML example to be more specific. abstractFoo is declared abstract because of security reasons.
Spring application context contains bean definitions, and Spring instantiates bean objects defined by these definitions.
Your current code obtains an object that was created from the named bean definition, and changes its property. However, abstract beans are never instantiated as objects, they exist only in the form of definitions which are inherited by definitions of concrete beans.
So, if you want to change properties of abstract beans, you need to change their definitions, that can be done using BeanFactoryPostProcessor. Note, however, that post-processors are applied during container startup, so if you want it to be actually "runtime", you this approach is not applicable.
Disclaimer: this is untested; off the top of my head. Not sure if it will work after the init phase.
You need to get in instance of a ConfigurableListableBeanFactory. Your appcontext probably is one, so you can probably cast it.
From there, get the bean definition and change the property.
ConfigurableListableBeanFactory clbf = (ConfigurableListableBeanFactory)context;
BeanDefinition fooDefinition = clbf.getBeanDefinition("abstractFoo");
MutablePropertyValues pv = fooDefinition.getPropertyValues();
pv.add(propertyName, newValue);
Maybe you need to re-register your beandefinition with the ConfigurableListableBeanFactory after that. I'm not 100% sure; you'll have to test that.
Keep in mind that if it works, it will only work for beans that are instantiated after the change.

Autowiring priority

<beans default-autowire="byType" />
means that all fields of beans will automatically have dependencies injected if there is no more than 1 bean with the desired type.
I wonder if there is a way to define some sort of priority order (based on naming convention for example) for the auto-wiring in the case where there are more than one bean of the desired type.
Thanks in advance.
Edit: I just want to add that i'm not allowed to use annotations such as #Component and #Qualifier in the project i'm currently working on.
No there is not, but you can override this behavior as needed for each bean e.g.specify something like this where required:
<beans default-autowire="byType" >
<bean id="..." autowire="byName">
....
</bean>
</beans>
From spring 2.5 upwards when using the <context:component-scan/> to autowire beans via #Autowired you can also add #Qualifier where needed to specify a bean by name if there are multiple beans of the same type.
As stated in the spring documentation there are a few different ways to specify autowiring:
no - do not autowire, this is the default
byType - property type must match bean type, if more than one bean of that type is exists then an exception is thrown
byName - bean name must match property name
constructor - basically the same as byType but for constructors, spring picks the constructor with the most matches
autodetect - same as byType unless there is no default constructor where it falls back to constructor autowiring

Categories