I have a problem with creating two beans of the same class but different qualifier name. Basically One bean is created with the annotations #Repository and the other one is creating inside #Configuration class.
This is the class that we wont two instances with different datasources:
#Repository ("someDao")
public class SomeDaoImpl implements SomeDao {
private NamedParameterJdbcTemplate jdbcTemplate;
#Autowired
public void setDataSource(DataSource dataSource) {
jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
}
}
And then we have a service like this:
#Service
public class SomeServiceImpl implements
SomeService {
#Resource(name = "someDao")
private SomeDao someDao;
#Resource(name = "someDaoAnotherDataSource")
private SomeDao someDaoAnotherDataSource;
}
My first bean is created by the annotation #Repository and the other one I declared in a Spring Configuration class:
#Configuration
#ComponentScan(basePackages = "mypackages")
public abstract class ApplicationRootConfiguration {
#Bean(name = "otherDataSource")
public DataSource otherDataSource() throws NamingException {
...
}
#Bean(name = "someDaoAnotherDataSource")
public SomeDao getSomeDaoAnotherDataSource(#Qualifier("otherDataSource")
DataSource dataSource) throws NamingException {
SomeDao dao = new SomeDaoImpl();
dao.setDataSource(dataSource);
return dao;
}
}
If I run my application, the property someDaoAnotherDataSource in SomeServiceImpl doesn't have my bean declared in the configuration class, it have the bean declared with the annotation Repository.
Also, if I running the same example in XML configuration it works:
<bean id="someDaoAnotherDataSource" class="SomeDaoImpl">
<property name="dataSource" ref="otherDataSource" />
</bean>
Any idea why is not autowiring the proper bean?
Thanks in advance.
Just a thought, instead of injecting the datasource into the method try the following
#Bean(name = "someDaoAnotherDataSource")
public SomeDao getSomeDaoAnotherDataSource() throws NamingException {
SomeDao dao = new SomeDaoImpl();
dao.setDataSource(otherDataSource());
return dao;
}
Although both should work.
Make sure that the name is correct in your #Resource annotation and instead of (or next to) specifing the name of the bean in the #Bean annotation, rename your method to the same.
#Bean(name = "someDaoAnotherDataSource")
public SomeDao someDaoAnotherDataSource() throws NamingException {
SomeDao dao = new SomeDaoImpl();
dao.setDataSource(otherDataSource());
return dao;
}
The name is basically an alias whereas the method name is used as the id of the bean. Could be that resolving isn't looking at aliases correctly. The same in xml would be
<bean id="getSomeDaoAnotherDataSource" name="someDaoAnotherDataSource" class="SomeDaoImpl">
<property name="dataSource" ref="otherDataSource" />
</bean>
Related
I have this project hierarchy:
A SpringConfiguration.java file with one Bean (SoapServiceBean).
A LoggerUtilsConfiguration.java with two beans (ConfigManager and LoggerManager).
SpringConfiguration imports LoggerUtilsConfigueration with an #Import.
The code:
#Configuration
#Import({com.myApp.LoggerUtilsConfiguration.class})
public class SpringConfiguration {
#Lazy
#Bean(name = "soapServiceBean")
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public SoapServiceBean soapServiceBeanInit(
#Qualifier("configManager") ConfigManager configManager ,
#Qualifier("loggerManager") LoggerManager loggerManager)
throws ServiceException, SystemException {
SoapServiceBean service = new SoapServiceBean();
service.setConfigManager(configManager);
service.setLoggerManager(loggerManager);
return service;
}
}
#Configuration
public class LoggerUtilsConfiguration {
#Bean(name = "configManager")
#Scope(BeanDefinition.SINGLETON)
public ConfigManager configManagerInit() {
ConfigManager cManager = new ConfigManager();
return cManager;
}
#Bean(name = "loggerManager")
#Scope(BeanDefinition.SINGLETON)
public LoggerManager loggerManagerInit() {
LoggerManager cManager = new LoggerManager();
return cManager;
}
}
My problema is that, "configManager" is a valid bean, but loggerManager throws this Exception:
No qualifying bean of type [com.myApp.LoggerManager] found for dependency:
expected at least 1 bean which qualifies as autowire candidate for this dependency.
Dependency annotations: {#org.springframework.beans.factory.annotation.Qualifier(value=loggerManager)}
Is very Strange, because If I copy the loggerManager Bean method into the main #Configuration class, the app starts with no problem and loggerManager is started with no problem.
"LoggerUtilsConfiguration" is not part of my App, is a Maven dependency external jar from another dev team. I have decompiled it and I cannot see anything strange, "configManager" and "loggerManager" has the same annotations with the same values except the bean name.
Any idea?
Solved.
My problem is the WebSphere, that store an old version of the third party JAR.
\was\wasprofiles\wp_profile80\installedApps\GUUPZN00Cell\MY-APP.ear\lib\LOGGER-LIB-1.0.0.jar
\was\wasprofiles\wp_profile80\installedApps\GUUPZN00Cell\MY-APP.ear\lib\LOGGER-LIB-1.0.1.jar
The version "1.0.0" LOGGER-LIB doesn't contains the bean "loggerManager" and WebSphere is loading this version of the library.
It seems that the file was blocked when websphere try to delete it. I had to stop the server to delete it properly.
If the 2 managers are singletons you can #Autowired them in.
If there is an existing bean called loggerManager of a different type then it wouldn't find yours, but it depends on how your classpath is set up.
#Configuration
#Import({com.myApp.LoggerUtilsConfiguration.class})
public class SpringConfiguration {
#Autowired
ConfigManager configManager;
#Autowired
LoggerManager loggerManager;
#Lazy
#Bean(name = "soapServiceBean")
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public SoapServiceBean soapServiceBeanInit()
throws ServiceException, SystemException {
SoapServiceBean service = new SoapServiceBean();
service.setConfigManager(configManager);
service.setLoggerManager(loggerManager);
return service;
}
}
Try to use #DependsOn:
#Lazy
#Bean(name = "soapServiceBean")
#DependsOn({ "configManager", "loggerManager" })
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public SoapServiceBean soapServiceBeanInit(
#Qualifier("configManager") ConfigManager configManager ,
#Qualifier("loggerManager") LoggerManager loggerManager)
throws ServiceException, SystemException {
SoapServiceBean service = new SoapServiceBean();
service.setConfigManager(configManager);
service.setLoggerManager(loggerManager);
return service;
}
Try providing autowire annotation to properly enable constructor injection like :
#Configuration
#Import({com.myApp.LoggerUtilsConfiguration.class})
public class SpringConfiguration {
#Lazy
#Autowired
#Bean(name = "soapServiceBean")
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public SoapServiceBean soapServiceBeanInit(
#Qualifier("configManager") ConfigManager configManager ,
#Qualifier("loggerManager") LoggerManager loggerManager)
throws ServiceException, SystemException {
SoapServiceBean service = new SoapServiceBean();
service.setConfigManager(configManager);
service.setLoggerManager(loggerManager);
return service;
}
}
The #Qualifier annotation is used to resolve the bean based on names while the #Autowired annotation provides constructor injection of beans. The #Bean annotation should support constructor injection without the need for #Autowired
when i am using #autowire to inject my dependencies in Configuration
class its giving me as null please refer the code below .
#Configuration
public class DataSourceConfig {
#Autowired
AppService appService;
#Bean
public BeanDefinitionRegistryPostProcessor beanPostProcessor() {
return new BeanDefinitionRegistryPostProcessor() {
public void postProcessBeanFactory(ConfigurableListableBeanFactory arg0) throws BeansException {
}
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanRegistry) throws BeansException {
createBeans(beanRegistry);
}
};
}
private void createBeans(BeanDefinitionRegistry beanRegistry,DataSourceConfigService ds) {
appService.getDbDetails();
appService is null here if i will call it using this way
BeanDefinitionRegistryPostProcessor beanPostProcessor(AppService
appService) then in AppServiceImpl class AppDao dependency will be null
}
}
//// Service
#Service
public class AppServiceImpl implements AppService{
#Autowired
AppDao ds;
#Override
public List<A> getDatabaseConfiguration() {
return ds.getDbDetails(); // here ds is null
}
}
//dao
#Repository
public class AppDaoImpl implements AppDao {
#Qualifier("nameParamJdbcTemplate")
#Autowired
public NamedParameterJdbcTemplate nameParamJdbcTemplate;
#Override
public List<A> getDbDetails() {
return nameParamJdbcTemplate.query(SELECT_QUERY, new DataSourceMapper()); // nameParamJdbcTemplate is null
}
// datasource config
#Configuration
public class DataSourceBuilderConfig {
#Bean(name = "dbSource")
#ConfigurationProperties(prefix = "datasource")
#Primary
public DataSource dataSource1() {
return DataSourceBuilder.create().build();
}
#Bean(name = "nameParamJdbcTemplate")
#DependsOn("dbSource")
#Autowired
public NamedParameterJdbcTemplate jdbcTemplate1(#Qualifier("dbSource") DataSource dbSource) {
return new NamedParameterJdbcTemplate(dbSource);
}
}
What i want is when ever my beanPostProcessor()
is executed i want all my dependent beans should be instantiated ie
#Autowired
AppService appService;
#Autowired
AppDao ds;
#Qualifier("nameParamJdbcTemplate")
#Autowired
public NamedParameterJdbcTemplate nameParamJdbcTemplate;
I am new to spring so any help or working examples would be great. Thanks
It is null because this #Configuration class also defines a BeanDefinitionRegistryPostProcessor that forces the context to create that bean very early on.
Because you are using field injection, the context has to resolve AppService bean but it can't yet because the post-processor have to be applied first.
Your configuration looks very complex so you may want to simplify it a bit:
Separate low-level infrastructure configuration from main configuration
Always define such post processor as public static method so that the context can invoke the #Bean method without having to construct the class first.
I use generally xml configuration in my Spring project under the three files:
applicationContext.xml:
This file contains the main xml configuration: component scan, annotation-config and also an include of two other xml configuration files:
applicationContext-db.xml
This file contains all database beans: dataSource, SessionFactory, ...
applicationContext-security.xml
This file contains all spring security config.
I need to use also Spring Security ACL, for this I created a configuration class:
AclMethodSecurityConfiguration.java
package com.medkhelifi.tutorials.todolist.conf;
/**
/* all imports goes here.
**/
#Configuration
#ImportResource({"classpath*:conf/applicationContext-db.xml"})
#EnableGlobalMethodSecurity (prePostEnabled = true, securedEnabled = true)
public class AclMethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
#Autowired
DataSource dataSource;
#Bean
public MethodSecurityExpressionHandler defaultMethodSecurityExpressionHandler() {
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
AclPermissionEvaluator permissionEvaluator = new AclPermissionEvaluator(aclService());
expressionHandler.setPermissionEvaluator(permissionEvaluator);
return expressionHandler;
}
#Bean
public JdbcMutableAclService aclService() {
return new JdbcMutableAclService(dataSource, lookupStrategy(), aclCache());
}
#Bean
public AclAuthorizationStrategy aclAuthorizationStrategy() {
return new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_ADMIN"));
}
#Bean
public PermissionGrantingStrategy permissionGrantingStrategy() {
return new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger());
}
#Bean
public EhCacheBasedAclCache aclCache() {
return new EhCacheBasedAclCache(
aclEhCacheFactoryBean().getObject(),
permissionGrantingStrategy(),
aclAuthorizationStrategy()
);
}
#Bean
public EhCacheFactoryBean aclEhCacheFactoryBean() {
EhCacheFactoryBean ehCacheFactoryBean = new EhCacheFactoryBean();
ehCacheFactoryBean.setCacheManager(aclCacheManager().getObject());
ehCacheFactoryBean.setCacheName("aclCache");
return ehCacheFactoryBean;
}
#Bean
public EhCacheManagerFactoryBean aclCacheManager() {
return new EhCacheManagerFactoryBean();
}
#Bean
public LookupStrategy lookupStrategy() {
return new BasicLookupStrategy(
dataSource,
aclCache(),
aclAuthorizationStrategy(),
new ConsoleAuditLogger());
}
}
My problem is the datasource autowired into Configuration file is null, I don't kwno if i missed something.
My XMLs files are all under: src/main/resources/conf/
There is my datasource bean definition in applicationContext-db.xml
<!-- DATASOURCE -->
<bean name="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${database.driver}"/>
<property name="url" value="${database.url}"/>
<property name="username" value="${database.username}"/>
<property name="password" value="${database.password}"/>
</bean>
I already used this bean into Sessionfactory bean defined in the same applicationContext-db.xml file.
PS: When I remove the extended class GlobalMethodSecurityConfiguration my datasource is defined, but I need this org.springframework.security.config.annotation.method.configurationclass to set up my Spring Security ACL configuration.
I found a way to define my datasource bean by using the BeanFactoryAware interface.
BeanFactoryAware is used to inject the BeanFactory object. This way we get access to the BeanFactory which created the object.
#EnableGlobalMethodSecurity (prePostEnabled = true, securedEnabled = true)
#Configuration
#ImportResource({"classpath:/conf/applicationContext-db.xml"})
public class AclMethodSecurityConfiguration extends GlobalMethodSecurityConfiguration implements BeanFactoryAware {
DataSource dataSource;
#Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.dataSource = beanFactory.getBean("dataSource", DataSource.class);
}
// rest of code goes here
}
I read that if we use this technic that means we are doing something wrong, I'll continue searching for a proper solution.
Please rename your bean as name="dataSource"
I'm working on a project in Spring using SpringMVC, i'm using the xml element <bean/> and i want to convert my code to #Bean
spring-bean.xml
<bean id="myDao" class="com.my.dao.EmployeImplDB" init-method="init"></bean>
<bean class="com.my.service.EmployeImplMetier" id="myMetier">
<property name="dao" ref="myDao"></property>
</bean>
how to convert xml to annotation #Bean?
You can write this way
#Repository
class EmployeImplDB{}
#Service
EmployeImplMetier{
#Autowired
EmployeImplDB myDao;
}
#Repository signifies that your bean is a DAO class
#Autowired injects dao class EmployeImplDB in the Service class
Like this:
#Bean(name = "myDao", initMethod = "init")
public EmployeDao myDao() {
EmployeDao eidb = new EmployeImplDB();
return eidb;
}
#Bean(name = "myMetier")
public Metier employeImplDB(EmployeDao myDao) {
Metier metier= new EmployeImplMetier(myDao);
return metier;
}
Note: Presuming that name of EmployeImplDB superclass (interface) is EmployeeDB.
I'm getting errors trying to inject resource dependencies into my unit testing.
My approach has been to write a TestConfig.java to replace the applicationContext.xml for production which manages the connections of the beans. So that I can run it with an in-memory database and just test components.
TestConfig.java
#Configuration
#EnableTransactionManagement
public class TestConfig {
#Bean
public DataSource dataSource() {
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("org.hsqldb.jdbcDriver");
ds.setUrl("jdbc:hsqldb:mem:testdb");
ds.setUsername("sa");
ds.setPassword("");
return ds;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(){
LocalContainerEntityManagerFactoryBean lcemfb
= new LocalContainerEntityManagerFactoryBean();
lcemfb.setDataSource(this.dataSource());
lcemfb.setPackagesToScan(new String[] {"com.dao","com.data"});
lcemfb.setPersistenceUnitName("MyTestPU");
HibernateJpaVendorAdapter va = new HibernateJpaVendorAdapter();
lcemfb.setJpaVendorAdapter(va);
Properties ps = new Properties();
ps.put("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
ps.put("hibernate.hbm2ddl.auto", "create");
lcemfb.setJpaProperties(ps);
lcemfb.afterPropertiesSet();
return lcemfb;
}
#Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager tm = new JpaTransactionManager();
tm.setEntityManagerFactory(this.entityManagerFactoryBean().getObject());
return tm;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){
return new PersistenceExceptionTranslationPostProcessor();
}
#Bean
public AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor()
{
return new AutowiredAnnotationBeanPostProcessor();
}
}
ProductsDaoTest.java
#ContextConfiguration(classes = { TestConfig.class })
#RunWith(SpringJUnit4ClassRunner.class)
public class ProductsDaoTest {
#Resource(name="com.dao.ProductsDao")
private ProductsDao testDao;
#Test
public void testSaveProduct() {
Product productA = new Product();
testDao.save(productA);
Set<Product> products = testDao.getAllProducts();
assertNotNull(products);
}
}
The error is Error creating bean with name 'com.dao.ProductsDaoTest': Injection of resource dependencies failed
So it can't find the ProductDao Bean which is a #Repository with a #Autowired sessionFactory.
So my guess is that because I'm not naming the beans using xml it can't find it, though I thought it should automatically pick it up from setPackagesToScan(). So is there a way to manually insert the Bean mapping so that it can be found?
Also more generally is this a reasonable way to go about testing Spring DAO configurations?
Regards,
Iain
I think you are trying to use wrong name of your DAO bean in #Resource annotation. Have you explicitly specify name of the ProductsDao bean using #Qualifier? If no, then as I remember by default the name of the bean will be productsDao. So you should inject your DAO like:
#Resource(name="productsDao")
private ProductsDao testDao;
If you have only one ProductDAO implementation then simply write:
#Autowired
private ProductsDao testDao;
or
#Inject
private ProductsDao testDao;
In case if you want to give specific name to DAO then use next construction:
#Respository
#Qualifier(name="specificName")
public class ProductDAO...
EDIT:
As Boris noted you should also specify which package to scan for defined beans (classes annotated with #Component, #Service, #Repository...). For this you should add #ComponentScan annotation to your configuration class definition.
#Configuration
#EnableTransactionManagement
#ComponentScan(basePackages = {"package_to_scan"})
public class TestConfig {...}