Can create HashMap with Spring but can't create Map - spring

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

Related

Spring use Autowired annotations gets wrong

<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<property name="loginUrl" value="/"/>
<property name="filterChainDefinitionMap" ref="chainFilterBuff" />
</bean>
<bean id="chainFilterBuff" class="org.moofie.test.security.FilterChainBean">
<property name="filterChainDefinitions">
<value>/test/login=anon</value>
</property>
</bean>
above is my spring config
private String filterChainDefinitions;
public String getFilterChainDefinitions() {
return filterChainDefinitions;
}
public void setFilterChainDefinitions(String filterChainDefinitions) {
this.filterChainDefinitions = filterChainDefinitions;
}
and this is my java code,it works fine with getter and setter,but I want to replace getter and setter with #autowired annotaion like this:
#Autowired
private String filterChainDefinitions;
it gets errors:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [java.lang.String] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1100)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:960)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:855)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:480)
... 34 more
So whats wrong with my code?or I should use other annotations?
The setter and getter way is working because, in your config XML you are calling the setter directly using the <property name="filterChainDefinitions"></property>.
#Autowired works on the bean that are declared explicitly.
If you want to use the #Autowired to set the filterChainDefinitions, then you must declare the it first like below:
<bean id="filterChainDefinitions" class="java.lang.String">
<constructor-arg value="/test/login=anon"/>
</bean>

Spring 3 Annotations with hibernate CRUD operations : #Autowired not working as expected

I'm currently using Spring 3 annotations along with hibernate 3 for the database connectivity. I also have to be using spring tiles.
My spring-servlet.xml is:
<context:annotation-config />
<context:component-scan base-package="com.xxx.controller,com.xxx.dao,com.xxx.service" />
<mvc:annotation-driven />
<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver"
id="viewResolver">
<property name="viewClass">
<value>
org.springframework.web.servlet.view.tiles2.TilesView
</value>
</property>
</bean>
<bean class="org.springframework.web.servlet.view.tiles2.TilesConfigurer"
id="tilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/plugin/impl/tiles/springtiles-defs.xml</value>
</list>
</property>
</bean>
//Is this required????
<!-- <bean id="MyDAO" class="com.xxxx.MyDAOImpl"></bean>
<bean id="MyService" class="com.xxxx.MyServiceImpl"></bean> -->
My controller class :
#Controller
public class myController {
#Autowired
private MyService myService;
public myController() {
}
#RequestMapping(value="/index.do", method = RequestMethod.GET)
protected ModelAndView Submit(HttpServletRequest request, HttpServletResponse response) throws Exception {
// TODO Auto-generated method stubs
System.out.println(" Inside the controller ");
</beans>
And my serviceImpl class:
#Service("MyService")
public class MyServiceImpl implements MyService{
#Autowired
MyDAO myDAO;
And my DaoImpl class :
#Repository/*("myDAO")*/
public class MyDAOImpl implements MyDAO{
List<String> clientList;
#Autowired
private SessionFactory sessionFactory;
private Session session;
private Session currentSession() {
return this.sessionFactory.getCurrentSession();
}
#Override
public List<ClientInfoBean> getClientList(String currentQrt) throws DataStoreException {
// TODO Auto-generated method stub
return (List<ClientInfoBean>) this.currentSession().
createCriteria("Select * from myTable);
}
It still gives the below exceptions.
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'MyController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.xxx.service.MyService com.xxx.controller.MyController.MyService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.xxx.service.MyService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:288)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1116)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.xxx.service.MyService com.xxx.controller.MyController.MyService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.xxx.service.MyService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:514)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:285)
... 97 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.xxx.service.MyService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:988)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:858)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:770)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:486)
... 99 more
So the problem is your packages:
You have definition of services and daos in: com.xxx.service and com.xxx.dao
and your implementation in: com.xxx.serviceImpl and com.xxx.daoImpl.
Add in also <context:component-scan base-package="com.xxx.serviceImpl,com.xxx.daoImpl"/>
Next problem you are facing is transactional management:
You havent defined it in spring configuration. This is an example how to do this:
<!-- Hibernate 3 Annotation SessionFactory Bean definition-->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.jdbc.batch_size">${batchSize}</prop>
</props>
</property>
</bean>
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
And after this you need to mark a method or your service implementation as #Transactional to make spring care of this.
The exception is clearly telling you that the bean is not configured
NoSuchBeanDefinitionException: No qualifying bean of type [com.xxx.service.MyService]
Can you check the case of the bean names that you given in annotations are matching with the parameter name. myService vs MyService.
Also adding a setter might be a good idea as spring can call setter to inject the dependency instead of using Reflection to inject it.
When you define
#Service("MyService")
public class MyServiceImpl implements MyService{
}
or
#Repository("MyDAO")
public class MyDAOImpl implements MyDAO{
}
you are actually telling spring to create bean with the name "MyService" & "MyDAO"
when you define like
#Autowired
private MyService myService;
#Autowired
private MyDAO myDAO;
you are asking from spring to give bean(s) with the name "myService" & "myDAO".
Since spring creates bean with the name which is different from what are you asking, it is giving the error.
You have to keep name of the bean in the #Service & #Repository annotation same as the variable name for the Interface.
#Service("myService")
public class MyServiceImpl implements MyService{
}
private MyService myService;
As you qualified your service as "MyService" , you can add qualifier as below to find it. By default spring should autowire by type , so component scan should load your service. If you are defining beans partially in xml and expecting other services to be autowired, you have to add in your spring-servlet.xml
#Autowired
#Qualifier("MyService")
private MyService myService;
Also change your controller class as MyController instead of myController.
And remove the constructor myController(), spring will construct for you controller bean. Try to remove all your constructors in all your spring bean classes, spring will construct for you. For the beginning you can avoid qualifying the beans, remove the names in brackets( "MyService", "MyDao" etc....)
Use
#Service
public class MyServiceImpl implements MyService
Instead of
#Service("MyService")
public class MyServiceImpl implements MyService{

Unable to Autowire a bean of type String

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.

jersey-spring3: Injecting Jersey OAuth resource into Spring managed Bean

I am trying to insert a Jersey 2.7 resource withing a Spring managed bean. Specifically, I want to inject OAuth1Signature within a Spring bean like so:
#Component
public class OAuthManager {
#Inject
private OAuth1Signature oAuthSignature;
private void someMethod() {
String signature = oAuthSignature.generate(oauthRequest, params, secrets);
}
}
I have tried using instructions provided within the HK2 Spring integration document: HK2 Spring Integration. Following the document, I added this to my spring xml configuration:
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="hk2">
<bean class="org.jvnet.hk2.spring.bridge.api.SpringScopeImpl" >
<property name="ServiceLocatorName" value="HK2ToSpringTest" />
</bean>
</entry>
</map>
</property>
</bean>
<bean id="org.glassfish.jersey.oauth1.signature.OAuth1Signature"
class="org.glassfish.jersey.oauth1.signature.OAuth1Signature"
scope="hk2"
lazy-init="true" />
However, I keep getting this exception when I start my webapp:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [org.glassfish.hk2.api.ServiceLocator] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:952)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:821)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:735)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:795)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:723)
OAuth1Signature documentation states that the ServiceLocator is supposed to be injected by HK2 framework which Jersey 2.7 uses. I am very confused on how I can get Spring to instantiate OAuth1Signature for me using the jersey-spring3 bridge since it does not seem to know where the Service locator should come from.
I have tried searching through StackOverflow and other Jersey message boards, but most of them deal with the opposite use case (injecting spring beans in a Jersey resource). Any help on this would be greatly appreciated !
I have recently done the development for OAuth in my project where I used Jersey 2.9.1 with Spring.
Below is what needs to be done to autowire the "OAuth1Signature's" instance in the Spring as we require hk2 to spring bridge to inject the hk2 services in the spring.
1.Define the custom hk2 scope
#Bean
public static CustomScopeConfigurer scopeConfigurer() {
Map<String, Object> scopeMap = new HashMap<String, Object>();
SpringScopeImpl hk2SpringScope = new SpringScopeImpl();
CustomScopeConfigurer customScopeConfigurer = new CustomScopeConfigurer();
hk2SpringScope.setServiceLocatorName("hk2SpringLocator");
scopeMap.put("hk2", hk2SpringScope);
customScopeConfigurer.setScopes(scopeMap);
return customScopeConfigurer;
}
2.Define the OAuth1Signature bean in "hk2" scope
#Bean(name = "oauth1Signature")
#Scope("hk2")
public OAuth1Signature getOAuth1Signature() {
ServiceLocator hk2ServiceLocator = ServiceLocatorFactory.getInstance()
.find("hk2SpringLocator");
OAuth1Signature oAuth1Signature = new OAuth1Signature(hk2ServiceLocator);
return oAuth1Signature;
}
3.After you are done with above 2 steps, you are ready to the autowire the "OAuth1Signature".
#Autowired
private OAuth1Signature oAuth1Signature;
Cheers

Error injecting a map using spring/JSR-330

I have 2 maven projects, a web-app, and a 'service' project. I am using spring to wire everything together. I would like to create a map in my application-context.xml, and have that injected into my class. When I try to start my web application I get an error message.
Here is my class:
#Named("tranformer")
public class IdentifierTransformerImpl implements IdentifierTransformer {
private Map<String, String> identifierMap;
#Inject
public IdentifierTransformerImpl(
#Named("identifierMap")
final Map<String, String> identifierMap) {
this.identifierMap= identifierMap;
}
and the application-context.xml:
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.0.xsd"
<util:map id="identifierMap" map-class="java.util.HashMap">
<entry key="Apple" value="fruit"/>
<entry key="BlackBerry" value="fruit"/>
<entry key="Android" value="robot"/>
<util:map>
<context:component-scan base-package="com.example" />
I get the following error:
..... 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: {#javax.inject.Named(value=identifierMap)
This works when I define a string in my application-context, and constructor inject it into a class, how can I do the same for a map?
I think Map collection is not supported by #Inject or #Autowired annotation (see: Spring can't autowire Map bean). However I managed to autowire a Map by annotating it as a resource as suggested by that answer. Try this:
#Resource(name="identifierMap") private Map<String, String> identifierMap;
The downside is ofcourse that isn't a constructor autowiring, but a field. I haven't found a way of doing it through constructor autowiring yet
If that is a direct copy/paste of your xml file, you aren't ending your <util:map> tag. You're missing a / in the second one.
With constructor injection.
#Inject
public IdentifierTransformerImpl(
#Value(value = "#{identifierMap}")
final Map<String, String> identifierMap) {
this.identifierMap= identifierMap;
}
Not ideal but Spring declines to provide a better option.
Check out more details at https://jira.spring.io/browse/SPR-8519

Resources