#Autowired on setter function does not look at the property name (like autowired in XML does) - spring

I am moving from XML to annotations.
I have the interface types House and My , and class types HouseImpl and MyImpl. Spring injects an MyImpl instance into and MouseImpl instance,
public class HouseImpl implements House
private My my;
public My getMy2() {
return my;
}
#Autowired
public void setMy2(My my) {
this.my = my;
}
So the property in HouseImpl is called my2.
In the Spring configuration file,
<context:annotation-config></context:annotation-config>
<bean
id="house"
class="....HouseImpl"
>
...
</bean>
<bean
id="my"
class="my.test.own.spring_book_annotations.MyImpl"
>
</bean>
<bean
id="my2"
class="my.test.own.spring_book_annotations.MyImpl2"
>
</bean>
If the configuation is in XML, so there is autowired="byName" in the house configuration, and no #Autowired annotation, then bean my2 is injected, because the property name is my2 (setMy2 is the method). But when we use annotations bean my is injected, because the name of the argument of setMy2 is my.
My question is why #Autowired on the setter function does not look at the property name.

When #Autowired is used on a setter and there are multiple matching types, the container will look at the parameter name to find the bean to inject. In your case, the parameter is My my, so the my bean will be injected. You can change the parameter to My my2, or use #Qualifier("my2") to inject the my2 bean.
If you want to use the field name, place #Autowired on the field itself to use field-injection.

Your code is like this
#Autowired
public void setMy2(My my) {
this.my = my;
}
When you write annotation #Autowired, it will take the bean with setXXX name....here XXX is My2.
Hence your bean with my2 id is injected.
In order to specify the bean with id as my user #Qualifier annotation.
#Autowired
#Qualifier("my")
public void setMy2(My my) {
this.my = my;
}

Related

How do I inject a bean in spring which is part of a class declared with #component tag

My spring config is set to use auto scanning for beans.
<context:annotation-config/>
<context:component-scan base-package="mypackage" />
I have a class that is declared with #Component
#Component
class A{
private InterfaceB b;
}
This InterfaceB is part of a jar file.
InterfaceBImpl implements InterfaceB{
// some contract here
}
I am getting an error from spring saying it cannot find a matching bean of type InterfaceB.
How can I inject that bean into the class?
private InterfaceB b in A has to be marked with #Autowired
But that doesn't enough, the InterfaceBImpl has to be a bean, too: or #Component, or as a <bean> in the xml config.
You have to declare a bean with the type B in your xml. Spring will automatically pick it up where you annotate a field with #Autowired.
Below is an example:
#Component
class A {
#Autowired
private B myB;
//other code
}
And in your xml:
<context:annotation-config/>
<context:component-scan base-package="mypackage" />
<bean id="myB" class="mypackage.InterfaceBImpl" />
Spring will see that A depends on B, looks in the context and sees that it has an implementation of B, which is InterfaceBImpl and inject it into A.
If you have control over the sources of InterfaceBImpl, add a #Component annotation to make Spring creating a bean be available for auto wiring.
If InterfaceBImpl cannot be changed, you can 1) extend it and annotate the extension or 2) you can create a configuration creating the bean:
1)
#Component
class MyInterfaceBImpl extends InterfaceBImpl {
}
2)
#Configuration
class MyAdditinalBeans {
#Bean
public InterfaceB interfaceB() {
return new InterfaceBImpl();
}
}

multiple instance of autowired bean

When a bean is autowired, does it create multiple instances of the class?
Here's an example;
public class ClassA {
#Autowired
private ClassB classB;
public ClassB getClassB() {
return classB;
}
public void setClassB(ClassB classB) {
this.classB = classB;
}
// using ClassB in method 1
public void useClassBmethod1() {
// currently using autowired ClassB instance
classB.doSomething();
}
// using ClassB in method 2
public void useClassBMethod2() {
// need a new instance of ClassB but through the same autowired bean
ClassB classb = getClassB();
}
}
public class ClassB {
public void doSomething() {}
}
So my question is, does autowiring a bean know how to create a new instance of a bean when needed or this is left to the programmer to decipher?
Thanks for helping out.
It depends on attribute scope of bean tag. If scope="singleton" which is by default then each time you will get single instance and if scope="prototype" then you will get different instances. And it doesn't depend on autowire.
<bean class="ClassB" scope="prototype">
By using #Autowired you instruct classloader to associate any class instance available in container to associate with the callee. You need to make sure that you have made an entry to instantiate the bean in your config file like <bean id="test" class="xxx.Test" />. Also you might want to check scopes too.
If you have multiple instances of same class define with different names then with #Autowired you need to provide specific name that you want to use with the help of qualifier.
by default all beans are singleton so only one instance will be created, more about scopes http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/beans.html#beans-factory-method-injection

Injecting property using #Value to abstract class

I have an abstract class in which I am trying to use the #Value annotation to inject value from a property file
public abstract class Parent {
#Value ("${shared.val}")
private String sharedVal;
public Parent() {
//perform common action using sharedVal
}
}
#Component
public class ChildA extends Parent {
Param a1;
#Autowired
public ChildA (Param a1) {
super();
this.a1 = a1;
}
}
I am getting NullPointerException since sharedVal is not set. I tried adding #Component stereotype on the abstract class and still the same thing.
Can I inject value into abstract class this way? If not how can accomplish this?
I think you'll find the sharedVal is being set, but you're trying to use it too soon in the constructor. The constructor is being called (must be called) before Spring injects the value using the #Value annotation.
Instead of processing the value in the constructor, try a #PostContruct method instead, eg:
#PostConstruct
void init() {
//perform common action using sharedVal
}
(or alternatively, implement Spring's InitializingBean interface).
Can I inject value into abstract class this way?
Abstract classes cannot be instantiated, so nothing can be injected into the abstract class. Instead , you should inject the value to its concrete subclass.
Make sure your concrete subclass is marked as #Component stereotype and being "component scanning" by Spring . #Component on the abstract class is not needed as it cannot be instantiated.
Update : I finally figure out that you are trying to access the injected value inside the constructor but found that the value is not set. It is because Spring will inject the value after the bean is instantiated . So if constructor injection is not used , the injected value cannot be accessed inside the constructor . You can use #PostContruct or implementing InitializingBean as suggested by Matt.
Following shows if XML configuration is used :
<context:property-placeholder location="classpath:xxxxx.properties" ignore-unresolvable="true" />
<bean id="parent" class="pkg.Parent" abstract="true" init-method="postConstruct">
<property name="sharedVal" value="${shared.val}" />
</bean>
<bean id="child" class="pkg.ChildA" parent="parent">
Perform your common action using sharedVal inside Parent#postConstruct()

Why do the protected fields of type String not get Autowired, while other beans do

I am trying to set value of protected String field in a annotation configured bean using property-override mechanism. It throws following exception unless I add a setter for the field in the bean.
org.springframework.beans.NotWritablePropertyException: Invalid property 'cookie' of bean class [com.test.TestBean]: Bean property 'cookie' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
To compare I also have another protected field which is of type of another class. Bean of the other class is defined in XML. This field gets properly autowired.
Here's the first bean
#Component("testBean")
public class TestBean {
protected #Autowired(required=false) String cookie;
protected #Autowired InnerBean innerBean;
public String getCookie() {
return cookie;
}
public void setCookie(String cookie) {
this.cookie = cookie;
}
public InnerBean getInnerBean() {
return innerBean;
}
}
Here's InnerBean
public class InnerBean {
private String value;
public void setValue(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
Spring configuration file - only interesting bits
<context:property-override location="beans.properties"/>
<context:component-scan base-package="com.test"></context:component-scan>
<context:annotation-config></context:annotation-config>
<bean id="innerBean" class="com.test.InnerBean">
<property name="value">
<value>Inner bean</value>
</property>
</bean>
beans.properties
testBean.cookie=Hello Injected World
Main
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("test.xml");
TestBean bean = context.getBean(TestBean.class);
System.out.println("Cookie : " + bean.getCookie());
System.out.println("Inner bean value : " + bean.getInnerBean().getValue());
}
Output
Cookie : Hello Injected World
Inner bean value : Inner bean
If I just comment out the setter for cookie in TestBean, I get the mentioned NotWritablePropertyException exception. Is there a difference between autowiring a bean and autowiring a property?
#Autowired should only be used when you want to wire up a Spring bean to another bean.
Properties are set by PropertyOverrideConfigurer which is a different process to autowiring, and doesn't use the #Autowired annotation. That #Autowired annotation on the cookie property is unnecessary and probably confusing Spring's bean factory. I expect that simply removing the annotation should fix the problem for you, ie:
protected String cookie;
protected #Autowired InnerBean innerBean;
Spring is capable of setting properties even if they are private or protected.

Autowired not working as expected

I'm using Spring Roo and want to access a bean within of Controller class which has following configuration in applicationContext.xml:
<bean class="com.reservation.jobs.Configuration" id="jobsConfiguration" autowire="byType">
<property name="skipWeeks" value="4" />
</bean>
The configuration class itself is:
package com.reservation.jobs;
public class Configuration {
private int skipWeeks;
public void setSkipWeeks(int value) {
System.out.println("SkipWeeks set auf: " + value);
this.skipWeeks = value;
}
public int getSkipWeeks() {
return this.skipWeeks;
}
}
In my Controller I thought that a simple Autowired annotation should do the job
public class SomeController extends Controller {
#Autowired
private com.reservation.jobs.Configuration config;
}
During startup Spring prints the message within the setSkipWeeks method. Unfortunately whenever I call config.getSkipWeeks() within the controller it returns 0.
Have I to use the getBean method of the ApplicationContext instance or is there some better way?
autowire="byType" is redundant. It indicates that fields of the Configuration class should be autowired, and you have just one primitive. So remove that attribute.
Apart from that, config.getSkipWeeks() must return 4 unless:
you are using a different instance (made by you with new)
you have called the setter somewhere with a value of 0

Resources