Autowiring is not working when configured through XML - spring

class ConfigurationDetails {
private #Resource String esHostURL;
private #Resource int maxMessageCounter;
private #Resource String queueName;
// Assume : This class has all getter and setter methods and a default constructor
}
Another Class
public class SpringMessageListener implements MessageListener {
#Resource ConfigurationDetails configDetails; // With getter and setter method for this
............
..........
And in my XML
<bean id="aListener" class="com.vzw.es.cosumer.SpringMessageListener" autowire="byName"/>
<bean id="configDetails" class="com.vzw.es.pojo.ConfigurationDetails" autowire="byName">
<property name="esHostURL" value="http://obsgracstg-db0.odc.vzwcorp.com:9200"/>
<property name="maxMessageCounter" value="500"/>
<property name="queueName" value="ES_queue"/>
</bean>
Now the bean with id configDetails is not getting autowired meaning when I debug the code and see the configDetails in class SpringMessageListerner it is showing null. But when I explicitly do the appContext.getBean("configDetails") it gives me the not null Object.
Why is the Autowiring is not working? Am I missing anything?

Spring doesn't, by default, look for #Autowired, #Resource, or #Inject annotations to autowire your beans. You need to tell it to look for them with
<context:component-scan base-package="com.yourpackage.some" />
// or, in this case, <context:annotation-config />
with this, Spring will scan the classes in the package and inject beans for which an #Autowired or #Resource exists.
Don't forget to add the namespace declarations
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd">
More importantly
class ConfigurationDetails {
private #Resource String esHostURL;
private #Resource int maxMessageCounter;
private #Resource String queueName;
// Assume : This class has all getter and setter methods and a default constructor
}
Although you can autowire String and int types, this is usually considered bad practice. Instead remove the #Resource annotation here and add getters and setters for each of the fields.
The property element in the <bean> declaration takes care of setting those fields.

Related

Why `autowire=byType` will also inject beans by name?

I found something not clear about the autowire=byType behavior.
Java code under package my:
public class User {
private String name;
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class UserService {
#Autowired
private User user1;
#Autowired
private User user2;
public String getNames() {
return user1.getName() + " & " + user2.getName();
}
}
Spring config:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd">
<context:component-scan base-package="my"/>
<context:annotation-config/>
<bean id="user1" class="my.User" autowire="byType">
<constructor-arg value="Freewind"/>
</bean>
<bean id="user2" class="my.User" autowire="byType">
<constructor-arg value="Lily"/>
</bean>
</beans>
Running code:
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService service = context.getBean(UserService.class);
System.out.println(service.getNames());
}
}
It's working well and prints:
Freewind & Lily
But I was expecting it should not work, because I used autowire="byType" when I defined the beans, and there are two beans with the same type User in UserService.
And, if I changed the name of the bean, say, user1 -> user999, it will report some error like No qualifying bean of type [my.User] is defined error.
It seems spring will automatic check the name even if I specified byType, which is strange.
PS: I've tested with spring 4.1.3.RELEASE and 3.2.2.RELEASE, same behavior.
<bean id="user2" class="my.User" autowire="byType">
<constructor-arg value="Lily"/>
</bean>
The autowire="byType" here means that you want to have (missing) dependencies injected into this bean byType. It only applies to the bean the attribute is placed on. In the xml namespace the default for all the beans could be set.
However in your case you are using actually using annotations (note <context:annotation-config /> is already implied by the usage of </context:component-scan />). Annotation driven injection (#Autowired, #Inject are always by type, #Resource uses a name or jndi lookup and as fallback by name).
When starting the application and scanning for components for each needed dependency the DependencyDescriptor is created. This class contains the details used for autowiring, it amongst other things contains the type and the name. The name, in case of a Field is derived from the actual name.

Could not instantiate bean class: Specified class is an interface

I know there are threads similar to this issue. Below is my class and I am configuring it in spring.xml file. Actually HumanResourceService is an interface having only one method.
#Endpoint
public class HolidayEndpoint {
#Autowired
private HumanResourceService humanResourceService;
#Autowired
public HolidayEndpoint(HumanResourceService humanResourceService) throws JDOMException {
this.humanResourceService = humanResourceService;
}
}
My problem is that in my spring.xml file, when I define HumanResourceService as bean, it cannot be instantiated as this is an interface. How can I mention an interface in spring configuration file. My spring.xml file is below
<bean id="holidayEndpoint" class="com.mycompany.hr.ws.HolidayEndpoint" autowire="constructor" >
<property name="humanResourceService" ref="humanResourceService" />
</bean>
<bean id="humanResourceService" class="com.mycompany.hr.service.HumanResourceService" />
You can't, Spring needs something it can make an instance from, the interface isn't enough.
In your spring.xml, the value of the class attribute for your bean with id="humanResourceService" should be the name of your implementation class, not the interface. Spring needs you to tell it what implementation class you want it to use for this.

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

Spring Autowire Fundamentals

I am a newbie in Spring and am trying to understand the below concept.
Assume that accountDAO is a dependency of AccountService.
Scenario 1:
<bean id="accServiceRef" class="com.service.AccountService">
<property name="accountDAO " ref="accDAORef"/>
</bean>
<bean id="accDAORef" class="com.dao.AccountDAO"/>
Scenario 2:
<bean id="accServiceRef" class="com.service.AccountService" autowire="byName"/>
<bean id="accDAORef" class="com.dao.AccountDAO"/>
In AccountService Class:
public class AccountService {
AccountDAO accountDAO;
....
....
}
In the second scenario, How is the dependency injected ? When we say it is autowired by Name , how exactly is it being done. Which name is matched while injecing the dependency?
Thanks in advance!
Use #Component and #Autowire, it's the Spring 3.0 way
#Component
public class AccountService {
#Autowired
private AccountDAO accountDAO;
/* ... */
}
Put a component scan in your app context rather than declare the beans directly.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com"/>
</beans>
<bean id="accServiceRef" class="com.service.accountService" autowire="byName">
</bean>
<bean id="accDAORef" class="com.dao.accountDAO">
</bean>
and
public class AccountService {
AccountDAO accountDAO;
/* more stuff */
}
When spring finds the autowire property inside accServiceRef bean, it will scan the instance variables inside the AccountService class for a matching name. If any of the instance variable name matches the bean name in the xml file, that bean will be injected into the AccountService class. In this case, a match is found for accountDAO.
Hope it makes sense.

Spring - How do you set Enum keys in a Map with annotations

I've an Enum class
public enum MyEnum{
ABC;
}
than my 'Mick' class has this property
private Map<MyEnum, OtherObj> myMap;
I've this spring xml configuration.
<util:map id="myMap">
<entry key="ABC" value-ref="myObj" />
</util:map>
<bean id="mick" class="com.x.Mick">
<property name="myMap" ref="myMap" />
</bean>
and this is fine.
I'd like to replace this xml configuration with Spring annotations.
Do you have any idea on how to autowire the map?
The problem here is that if I switch from xml config to the #Autowired annotation (on the myMap attribute of the Mick class) Spring is throwing this exception
nested exception is org.springframework.beans.FatalBeanException: Key type [class com.MyEnum] of map [java.util.Map] must be assignable to [java.lang.String]
Spring is no more able to recognize the string ABC as a MyEnum.ABC object.
Any idea?
Thanks
This worked for me...
My Spring application context:
<util:map id="myMap">
<entry key="#{T(com.acme.MyEnum).ELEM1}" value="value1" />
<entry key="#{T(com.acme.MyEnum).ELEM2}" value="value2" />
</util:map>
My class where the Map gets injected:
public class MyClass {
private #Resource Map<MyEnum, String> myMap;
}
The important things to note are that in the Spring context I used SpEL (Spring Expression Language) which is only available since version 3.0. And in my class I used #Resource, neither #Inject (it didn't work for me) nor #Autowired (I didn't try this). The only difference I'm aware of between #Resource and #Autowired, is that the former auto-inject by bean name while the later does it by bean type.
Enjoy!
This one gave me fits but I was able to piece it together using David's answer and some other links (below).
do not change the names of the properties in the MapFactoryBean declaration.
ensure that key-type attribute points to the enum that you want to use as a key in the map.
Class
#Component
public class MyClass {
private Map<MyEnum, ValueObjectInterface> valueMap;
#Autowired
public void setValueMap(final Map<MyEnum, ValueObjectInterface> valueMap) {
this.valueMap= valueMap;
}
}
Enum
public enum MyEnum{
FOO ("FOO"),
BAR ("BAR"),
BAZ ("BAZ");
}
XML Config file:
<bean id="valueMap" class="org.springframework.beans.factory.config.MapFactoryBean">
<property name="targetMapClass">
<value>java.util.HashMap</value>
</property>
<property name="sourceMap">
<map key-type="com.company.packagepath.MyEnum">
<entry key="FOO" value-ref="valueObject1" />
<entry key="BAR" value-ref="valueObject2" />
<entry key="BAZ" value-ref="valueObject3" />
</map>
</property>
</bean>
<bean id="valueObject1" class="com.company.packagepath.ValueObject1" />
<bean id="valueObject2" class="com.company.packagepath.ValueObject2" />
<bean id="valueObject3" class="com.company.packagepath.ValueObject3" />
LINKS
Code Ranch
Spring MapFactoryBean example at mkyong.com
How assign bean's property an Enum value in Spring config file?
Application context
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd ">
<bean id="myProvider" class="com.project.MapProvider">
<property name="myMap" ref="myMap"/>
</bean>
<util:map id="myMap" key-type="com.project.MyEnum" value-type="com.project.ValueObject">
<entry>
<key><value type="com.project.MyEnum">FOO</value></key>
<ref bean="objectValue1"/>
</entry>
</util:map>
</beans>
Java class
package com.project;
public class MapProvider {
private Map<MyEnum, ValueObject> myMap;
public void setMyMap(Map<MyEnum, ValueObject> myMap) {
this.myMap = myMap;
}
}
Should be:
public class Mick {
private Map<MyEnum, OtherObj> myMap;
#Autowired
public void setMyMap(Map<MyEnum, OtherObj> myMap) {
this.myMap = myMap;
}
}
Have a look at http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-annotation-config
Updated
The problem is that according to the util schema, you cannot specify the key or value types. You can however to implement a MapFactoryBean of your own (just inherit from org.springframework.beans.factory.config.MapFactoryBean). One ceveat - notice that the generic definition (even thought erased in runtime) doesn't get in the way.
The <util:map> element has key-type, resp. value-type attributes, that represents the class of the keys, resp. the values. If you specify the fully qualified class of your enum in the key-type attribute, the keys are then parsed into that enum when creating the map.
Spring verifies during injection that the map's key and value types -as declared in the class containing the map- are assignment-compatible with the key and value types of the map bean. This is actually where you get the exception from.
You just need to use concrete Map class as HashMap and not abstract or interface:
public class Mick {
private HashMap<MyEnum, OtherObj> myMap;
#Autowired
public void setMyMap(HashMap<MyEnum, OtherObj> myMap) {
this.myMap = myMap;
}
}
public class AppConfig
{
#Bean
public HashMap<MyEnum, OtherObj> myMap() { .. }
}
If you have a Map with an Enum values as keys, then consider using Java's EnumMap implementation:
https://docs.oracle.com/en/java/javase/12/docs/api/java.base/java/util/EnumMap.html
Here you also have a Baeldung post with some examples on how to use it:
https://www.baeldung.com/java-enum-map

Resources