Error injecting a map using spring/JSR-330 - spring

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

Related

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.

#Autowired not working for interface

I am trying all the solutions from Google from last 4 days. but not working.
I am trying to autowire below Interface -
#Qualifier("roleAccessRepository")
#Repository
public interface RoleAccessRepository extends BaseJPACrudRepository<RoleAccess, Long> {
in PermissionEvaluator in following way.But its not working.
#Scope(proxyMode = ScopedProxyMode.INTERFACES, value = "prototype")
public class PermissionEvaluator implements org.springframework.security.access.PermissionEvaluator
{
#Autowired
RoleAccessRepository roleAccessRepository;
..........
Giving me error -
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: net.pa
ger.lrs.sql.db.RoleAccessRepository net.pager.lrs.security.PermissionEvaluator.roleAccessRepository;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying
bean of type [net.pager.lrs.sql.db.RoleAccessRepository] found for dependency: expected at least 1 b
ean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springf
But Repository defined in the same package and autowired in service class are working good.
#Service
#Transactional
public class AccountService extends BaseCrudService<Account> {
/** The account db. */
#Autowired
private AccountRepository accountDB;
}
My security.xml is as follows - which has base package net.pager.lrs which is parent directory.
<bean id="permissionEvaluator" class="net.pager.lrs.security.PermissionEvaluator">
<constructor-arg index="0">
Please help me.
Ok,
From the discussions above, I still think that the problem is with not having the concrete implementation of the Autowired interfaces. Just for the sake of common sense, if you do not provide an implementation, what will you execute using the reference of the Autowired interface.
There is a way where you do not define the implementation, spring can generate proxy beans and autowire, but that is of no use.
You might end up providing an anonymous implementation of the interface as well.

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

Autowiring is not working when configured through XML

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.

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

Resources