Unable to Autowire a bean of type String - spring

I have a bean as defined below which I want to autowire in to a Class which is defined as a bean in the Spring context file. But its not working, Strangely the other object bean types autowired in the same class are being autowired correctly.
Bean to Autowire is as below :-
<bean id="stringToAutowire" class="java.lang.String">
<constructor-arg value="true" />
</bean>
Class where its to be Autowired is :- I have tried annotating it with #Component .But no success.
public class AService {
#Autowired
private BDao bDao;
#Autowired
private String stringToAutowire;
........
}
context file is as :-
<context:annotation-config/>
<context:component-scan base-package ="PKG "/>
<bean id="aService" class="AService"/>
<bean id="bDao" class="BDao"/>
<bean id="stringToAutowire" class="java.lang.String">
<constructor-arg value="true" />
</bean>

In the Spring documentation:
http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/beans.html#beans-autowired-exceptions
There is this text "You cannot autowire so-called simple properties such as primitives, Strings, and Classes (and arrays of such simple properties). This limitation is by-design."
I have not found an exact specification of what happens in this case. In my experience Autowire of String properties is unreliable. Sometimes works, sometimes not. So I recommend avoiding autowire of string values.
In your case you are using both Autowire and constructor-arg. They are separate mechanisms. Only one is required.
Ditch Autowire for String.
Add a constructor to AService that takes, as the first argument, a string to assign to "stringToAutowire". The "constructor-arg" will specify what to pass for this constructor argument.

try using below:
#Autowired
#Qualifier("stringToAutowire")
private String someString;

You can not autowire simple properties such as primitives, Strings, and Classes (and arrays of such simple properties) and explicit dependencies in property and constructor-arg settings always override autowiring.
So drop #Autowired annotation from stringToAutowire and use with property.

Related

Singleton and Prototype in one Container

If there are two bean, and the bean b1 the scope is singleton, bean b2 the scope is prototype.In this case if the container is started then how many beans are created and to which scope it will go.
Two beans shall be created. One singleton and the other prototype.
If you are talking about two beans of same class, then also the scenario is same.
When you shall autowire the beans you would have to provide a qualifier attribute.
eg:
<bean id="a" class="package.classname" scope="prototype"/>
<bean id="b" class="package.classname" scope="singleton" />
During autowiring:
#Autowired
#Qualifier(id="a")
public package.classname instance1;
#Autowired
#Qualifier(id="b")
public package.classname instance2;

Is default constructor required in Spring injection?

I'm trying to inject a constructor that takes some arguments. After compiling Spring complains it couldn't find a default constructor (I haven't defined it) and throws BeanInstatiationException and NoSuchMethodException.
After defining a default constructor the exceptions don't appear anymore, however my object is never initialized with the argument constructor, only the default one is called. Does Spring really require a default constructor in this case? And if yes, how can I make it use the argument constructor instead of the default one?
This is how I wire everything:
public class Servlet {
#Autowired
private Module module;
(code that uses module...)
}
#Component
public class Module {
public Module(String arg) {}
...
}
Bean configuration:
<beans>
<bean id="module" class="com.client.Module">
<constructor-arg type="java.lang.String" index="0">
<value>Text</value>
</constructor-arg>
</bean>
...
</beans>
Stack trace:
WARNING: Could not get url for /javax/servlet/resources/j2ee_web_services_1_1.xsd
ERROR initWebApplicationContext, Context initialization failed
[tomcat:launch] org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'module' defined in URL [...]: Instantiation of bean failed;
nested exception is org.springframework.beans.BeanInstantiationException: Could not
instantiate bean class [com.client.Module]: No default constructor found; nested
exception is java.lang.NoSuchMethodException: com.client.Module.<init>()
Spring only "requires" a default constructor if you plan on instantiating it without any arguments.
for example, if your class is like this;
public class MyClass {
private String something;
public MyClass(String something) {
this.something = something;
}
public void setSomething(String something) {
this.something = something;
}
}
and you set it up in Spring like this;
<bean id="myClass" class="foo.bar.MyClass">
<property name="something" value="hello"/>
</bean>
you're going to get an error. the reason is that Spring instantiates your class new MyClass() then tries to set call setSomething(..).
so instead, the Spring xml should look like this;
<bean id="myClass" class="foo.bar.MyClass">
<constructor-arg value="hello"/>
</bean>
so have a look at your com.client.Module and see how its configured in your Spring xml
Most probably you are using component-scanning and since you define annotation #Component for class Module it tries to instantiate the bean. You do not need #Component annotation if You are using XML for bean definition.
Just faced the same problem, i guess till now you might have solved the problem.
Below is what you could have changed your bean configuration to,
<bean id="module" class="com.client.Module">
<constructor-arg value="Text"/>
</bean>

Can create HashMap with Spring but can't create Map

I can do this in my applicationContext with Spring (3.0.5):
<bean id="map" class="java.util.HashMap" scope="prototype" >
<constructor-arg>
<map key-type="java.lang.String" value-type="java.lang.String">
<entry key="Key 1" value="1" />
<entry key="Key 2" value="2" />
</map>
</constructor-arg>
</bean>
And in my controller, I can autowired my map like this:
#Autowired
#Qualifier("map")
private HashMap<String, String> map;
It works fine, but if I do this:
#Autowired
#Qualifier("map")
private Map<String, String> map;
I get that:
Caused by:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
matching bean of type [java.lang.String] found for dependency [map
with value type java.lang.String]: expected at least 1 bean which
qualifies as autowire candidate for this dependency. Dependency
annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true),
#org.springframework.beans.factory.annotation.Qualifier(value=map)}
My question is: Why I can't autowired my map with the interface when I can with the implementation ?
Thanks.
While declaring a bean of type collection, one cannot inject it via #Autowired. See below documentation from Spring:
4.11.3 Fine-tuning annotation-based autowiring with qualifiers
As a specific consequence of this semantic difference, beans which are
themselves defined as a collection or map type cannot be injected via
#Autowired since type matching is not properly applicable to them. Use
#Resource for such beans, referring to the specific collection/map
bean by unique name.
Thus instead of #Autowired, use #Resource:
#Resource
#Qualifier("map")
private Map<String, String> map;
Try to use #Resource instead of #Autowired
#Resource(name="map")
private HashMap<String, String> map;
Check out the tip in 3.9.3 Fine-tuning annotation-based autowiring with qualifiers of Spring's documentation

Can't use #Qualifier along with #Inject and autowire="byType"

I have the bean config:
<bean id="PostLoginUpdater" class="xyz.auth.PostLoginUpdater" autowire="byType" />
and
public class PostLoginUpdater implements PostLoginStatePersonalizer {
//#Qualifier("CustomerManager")
#Inject
//#Resource(name = "CustomerManager")
private CustomerManager customerManager;
public void setCustomerManager(CustomerManager customerManager)
{
this.customerManager = customerManager;
}
}
Because there are two beans that implement CustomerManager I get this error:
No unique bean of type [CustomerManager] is defined: expected single
matching bean but found 2
As you can see, I'v tried several combinations (#Inject along with #Qualifier, #Ressource, only #Qualifier) But I don't get rid of this error message.
According to Spring In Depth, #Qualifier can be used along with #Inject. Can't I used them together if I defined autowire="byType" in bean config?
And I don't use <context:annotation-config /> or <context:component-scan />
You should be able to use a combination of '#Inject' and '#Qualifier', if you have multiple beans of the same type. Here is how to configure it -
<bean id="PostLoginUpdater" class="xyz.auth.PostLoginUpdater" autowire="byType" />
<bean id="firstManager" class="xyz.manager.CustomerManager" autowire="byType" >
<qualifier>first</qualifier>
</bean>
<bean id="secondManager" class="xyz.manager.CustomerManager" autowire="byType" >
<qualifier>second</qualifier>
</bean>
If you had two beans of type 'CustomerManager' as shown above, you could use the snippet shown below for injection -
public class PostLoginUpdater implements PostLoginStatePersonalizer {
#Inject
#Qualifier("first")
private CustomerManager customerManager;
public void setCustomerManager(CustomerManager customerManager)
{
this.customerManager = customerManager;
}
}
Also, on a side note -
If you keep using one of the beans more often than another you could use the 'primary' attribute.
For example, in the above example, if you always tend to use 'firstManager', you could mark it as primary as shown below.
<bean id="PostLoginUpdater" class="xyz.auth.PostLoginUpdater" autowire="byType" />
<bean id="firstManager" class="xyz.manager.CustomerManager" autowire="byType" primary="true" >
</bean>
<bean id="secondManager" class="xyz.manager.CustomerManager" autowire="byType" >
<qualifier>second</qualifier>
</bean>
If you have above configuration, the following code will always injects 'firstManager' when no qualifier is used -
public class PostLoginUpdater implements PostLoginStatePersonalizer {
#Inject
private CustomerManager customerManager;
public void setCustomerManager(CustomerManager customerManager)
{
this.customerManager = customerManager;
}
}
It doesn't make any sense to try to autowire by type, and simultaneously specify a name. Choose one approach or the other.
I have also had trouble in the past trying to use #Qualifier with #Inject. One thing to note is that there are two annotations with that name, one in Spring and one in Java:
org.springframework.beans.factory.annotation.Qualifier
javax.inject.Qualifier
However, if using the spring framework one, then the suggested usage is to explicitly name your component via #Component or #Named [#Component("beanName")] (if annotated), or in the <bean> definition. Be aware that autowiring wants the bean name, not the Class name as in your example (i.e. do not use "CustomerManager"). For example, if you have two bean definitions like in Sashi's example:
<bean id="firstManager" class="xyz.manager.CustomerManager" autowire="byType" >
<qualifier>first</qualifier>
</bean>
<bean id="secondManager" class="xyz.manager.CustomerManager" autowire="byType" >
<qualifier>second</qualifier>
</bean>
then declare the field like this:
#Inject
#Qualifier("firstManager")
private CustomerManager customerManager;

Session object's autowired properties do not autowire if the session object is declared <aop:scoped-proxy>

Session object's autowired properties do not autowire if the session object is declared
<bean id="user" class="org.User" scope="session">
<aop:scoped-proxy/>
</bean>
The user objects proerty is #autowired but the property doesn't get autowired.
public class User
{
TemplateService templateService;
#Autowired
public void setTemplateService(TemplateService templateService) {
this.templateService = templateService;
}
}
I wonder why this is so.
Is replacing the autowire annotations with xml declarations the only solution. Are there any other solutions?
Thanks

Resources