spring Multi DataSource #Service annotation with existing error - spring

I have a code that is an error in the Spring Framework
Error Cause I know
So I do not know how to solve it the question.
I am being used with mybatis library
I had multi DataSource of two Account DataBase
I created a root-context.xml
-----------------------root-context.xml -----------------------------------------------------------
Oracle Account 1 Test1
<bean id="dataSourceTest1" class="org.apache.commons.dbcp.BasicDataSource" destroy-m
ethod="close">
<property name="driverClassName" value="net.sf.log4jdbc.DriverSpy"/>
<property name="url" value="jdbc:log4jdbc:oracle:thin:#111.111.1111.1111:1111:Test1"/>
<property name="username" value="TEST1"/>
<property name="password" value="TEST1"/>
<property name="maxIdle" value="200"/>
<property name="maxActive" value="200"/>
<property name="minIdle" value="5"/>
</bean>
<bean id="sqlSessionFactoryTest1" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSourceTest1" />
<property name="mapperLocations" value="classpath*:test/service/server/test1/**/*.xml" />
</bean>
<bean id="sqlSessionTest1" class="org.mybatis.spring.SqlSessionTemplate" name="sqlSessionTest1">
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactoryTest1" />
</bean>
<mybatis-spring:scan base-package="test.service.server.test1" template-ref="sqlSessionTest1" />
Oracle Account test2
<bean id="dataSourceTest2" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="net.sf.log4jdbc.DriverSpy"/>
<property name="url" value="jdbc:log4jdbc:oracle:thin:#222.222.2222.222:2222:Test2"/>
<property name="username" value="Test2"/>
<property name="password" value="Test2"/>
<property name="maxIdle" value="200"/>
<property name="maxActive" value="200"/>
<property name="minIdle" value="5"/>
</bean>
<bean id="sqlSessionFactoryTest2" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSourceTest2" />
<property name="mapperLocations" value="classpath*:test/service/server/test2/**/*.xml" />
</bean>
<bean id="sqlSessionTest2" class="org.mybatis.spring.SqlSessionTemplate" name="sqlSessionTest2">
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactoryTest2" />
</bean>
<mybatis-spring:scan base-package="test.service.server.test2" template-ref="sqlSessionTest2"/>
-----------------------root-context.xml END ---------------------------------------------------------
i am not used context:component-scan
<!-- <context:component-scan base-package="test.service.server.test1.test1service"/>-->
<!-- <context:component-scan base-package="test.service.server.test2.test2service"/>-->
I use the SpringJUnit4 each unit test
Were sequentially to (DataSourceTest and SqlSessionFactory Test and SqlSession Test mapperScanTest).
did not have any problems until mapperScanTest.
However, an error occurs when star using the annotation # Service
------------------------------------------service interface code ------------------------------------
public interface Test2_SERVICE {
public List<Test2_VO> GET_ListVO();
}
-------------------------------------------implement service code----------------------------------
#Service("Test2_SERVICE") *//<--Error annotaion*
public class Test2_SERVICEIMPLE implements Test2_SERVICE{
#Resource
Test2_MAPPER mapper;
#Override
public List<Test2_VO> GET_ListVO() {
return mapper.GET_ListMapperVO();
}
}
---------test Code------------------------------
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "file:src/main/**/*-context.xml" })
public class TestService {
Logger logger = Logger.getLogger(Thread.currentThread().getClass());
#Autowired
#Qualifier("Test2_SERVICE")
Test2_SERVICE test2_SERVICE;
#Override
public void testString() {
logger.info("---------------------");
List<Test2_VO> listVO = test2_SERVICE.GET_ListVO();
logger.info(listVO );
logger.info("---------------------");
}
}
Error Messages-----------------------------------
Caused by:
org.springframework.context.annotation.ConflictingBeanDefinitionException:
Annotation-specified bean name 'Test2_SERVICE' for bean class
[test.service.server.test2.test2service.Test2_SERVICE] conflicts with
existing, non-compatible bean definition of same name and class
[test.service.server.test2.test2service.Test2_SERVICEIMPLE]
------------------------------------------------end---------------------------------------------
#Service("Test2_SERVICE") *//<--Error annotaion*
The problem did not exist until the object Test2_MAPPER
However, the error begins in Test2_SERVICE
# Service ("Test2_SERVICE") Where there is only used here (Test2_SERVICEIMPLE).
Because of this problem
I am suffering for three days..
Somebody tell me solve the problem for this error message.
Thank you for reading my article.

The problem is that you create a bean with the name "Test2_SERVICE" for Test2_SERVICEIMPLE with this annotation:
#Service("Test2_SERVICE")
//creates the bean with id="TEST2_Service" of the type Test2_SERVICEIMPLE
public class Test2_SERVICEIMPLE implements Test2_SERVICE
and then assign exactly this Test2_SERVICEIMPLE bean to the interface Test2Service
#Autowired
#Qualifier("Test2_SERVICE")
//here you assign the bean of the not matching type Test2_SERVICEIMPLE to
//a variable of type Test2_SERVICE
Test2_SERVICE test2_SERVICE;
That means that the interface wants to use the bean for the implementation...
So just remove/change the #Qualifier("Test2_SERVICE") or change the name of the #Service("Test2_SERVICE")
How to autowire annotation qualifiers and how to name autodetected components

Related

Embedded H2 Database for Spring unit test with Liquibase: No data in tables when running test

I have embedded H2 database for my Spring unit tests. The tables and data should be initialized with Liquibase. However, when a test is running, there are no data in the table.
I'm using Spring 4.2.1, Liquibase 4.7.1 and H2 2.1.210.
Below is my implementation:
The datasource is declare in .xml file
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.h2.Driver" />
<property name="url" value="jdbc:h2:mem:test;MODE=Oracle;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE" />
<property name="username" value="test" />
<property name="password" value="test" />
</bean>
<bean id="liquibase" class="liquibase.integration.spring.SpringLiquibase">
<property name="dataSource" ref="dataSource" />
<property name="changeLog" value="classpath:liquibase/changelog/sil_client_init.h2.sql" />
<property name="contexts" value="test" />
</bean>
<!-- Session factory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:hibernate-config.xml" />
</bean>
<!-- Transaction manager -->
<bean id="txManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
The sil_client_init.h2.sql file contains SQL contains changeset for creating and inserting several data in the table.
I have a super class which load the context, including the "liquibase" bean declared above.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath*:applicationContext.xml" })
#Ignore
public class SpringApplicationContextIT {
#Before
public void setUp() {
BasicConfigurator.configure();
FacesContextMocker.mockFacesContext();
assertNotNull(applicationContext);
}
#Autowired
private ApplicationContext applicationContext;
}
From which my test class inherits
public class ClientDAOTest extends SpringApplicationContextIT {
#Autowired
private IClientDAO simpleClientDAO;
#Test
#Transactional
public void getAllClients() throws ClientDAOException {
simpleClientDAO.find();
}
When running getAllClients(), the context are loaded and there is log showing that my changesets Liquibase were running. However, when the test arrives at simpleClientDAO.find(), my Client table is empty.
Any idea of how to fix, how this could happen or how I could investigate the reason would be appreciated. Thank you so much in advance!
For those who might have the same problem, turn out the datasource is properly loaded but my sessions are not correctly connected.
I had to specify a package to scan for my sessionFactory bean:
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan">
<value>com.myApp.dao.entity</value>
</property>
<property name="configLocation" value="/WEB-INF/classes/hibernate-config.xml" />
</bean>

Autowire Jdbc template

I am trying to auto-wire JDBC template and I'm getting a null pointer exception (template is null). What could be the problem?
#Autowired
template JdbcTemplate;
This is my application context xml:
<bean ..>
<mvc:annotation-driven />
<context:component-scan base-package="igate.dto" />
<context:component-scan base-package="igate.dao" />
<context:component-scan base-package="igate.service" />
<context:component-scan base-package="igate.controller" />
<context:component-scan base-package="igate.logs" />
<context:component-scan base-package="igate.testcases" />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp" />
</bean>
<bean id="ds" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:#172.21.17.5:1521:oraten" />
<property name="username" value="lab01trg21" />
<property name="password" value="lab01oracle" />
</bean>
<bean id="template" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="ds"/>
</bean>
</beans>
Instead of this code:
#Autowired
template JdbcTemplate;
You need:
#Autowired
JdbcTemplate template;
The bean you try to inject in is not in the spring context;
No setter for the JdbcTemplate
You try to use the template in the constructor before the template is injeted
One reason for this error is to mix autowiring with manual
creation of beans.
For instance, you have a service class that autowires a bean.
#Service
public class CarService {
#Autowired
public JdbcTemplate jdbcTemplate;
// service code
}
But later intead of
#Autowired
private CarService carService;
you do:
CarService carService = new CarService();

multiple databases with Spring Data JPA

I'm trying to use Spring Data JPA with 2 databases in project. But an exception is triggered when I'm trying to run the application:
07:21:47.734 [main] ERROR o.s.web.context.ContextLoader - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'deviceRepository': Injection of persistence dependencies failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [javax.persistence.EntityManagerFactory] is defined: expected single bean but found 2
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.postProcessPropertyValues(PersistenceAnnotationBeanPostProcessor.java:342) ~[spring-orm-3.1.0.RELEASE.jar:3.1.0.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1106) ~[spring-beans-3.1.0.RELEASE.jar:3.1.0.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-3.1.0.RELEASE.jar:3.1.0.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456) ~[spring-beans-3.1.0.RELEASE.jar:3.1.0.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294) ~[spring-beans-3.1.0.RELEASE.jar:3.1.0.RELEASE]
...
Here is my applicationContext.xml
<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource1">
<property name="driverClassName" value="${database.driverClassName}"/>
<property name="url" value="${database.url1}"/>
<property name="username" value="${database.username1}"/>
<property name="password" value="${database.password1}"/>
<property name="testOnBorrow" value="true"/>
<property name="testOnReturn" value="true"/>
<property name="testWhileIdle" value="true"/>
<property name="timeBetweenEvictionRunsMillis" value="1800000"/>
<property name="numTestsPerEvictionRun" value="3"/>
<property name="minEvictableIdleTimeMillis" value="1800000"/>
<property name="validationQuery" value="SELECT 1"/>
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager1">
<property name="entityManagerFactory" ref="entityManagerFactory1"/>
</bean>
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager1"/>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory1">
<property name="persistenceUnitName" value="persistenceUnit1"/>
<property name="dataSource" ref="dataSource1"/>
</bean>
<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource2">
<property name="driverClassName" value="${database.driverClassName}"/>
<property name="url" value="${database.url2}"/>
<property name="username" value="${database.username2}"/>
<property name="password" value="${database.password2}"/>
<property name="testOnBorrow" value="true"/>
<property name="testOnReturn" value="true"/>
<property name="testWhileIdle" value="true"/>
<property name="timeBetweenEvictionRunsMillis" value="1800000"/>
<property name="numTestsPerEvictionRun" value="3"/>
<property name="minEvictableIdleTimeMillis" value="1800000"/>
<property name="validationQuery" value="SELECT 1"/>
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager2">
<property name="entityManagerFactory" ref="entityManagerFactory2"/>
</bean>
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager2"/>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory2">
<property name="persistenceUnitName" value="persistenceUnit2"/>
<property name="dataSource" ref="dataSource2"/>
</bean>
Here is my DAO interface:
#Repository
public interface DeviceRepository extends JpaRepository<Device, DevicePK>,
JpaSpecificationExecutor<Device> {
}
I've read a lot about #PersistenceContext but I never saw usages with JpaRepository.
Well you do have 2 entitymanagers.
I've never used JPARepository, but if it works close to its counter parts on spring-data for nosql, Spring will enhance the class, and probably inject the EM on it. Your problem is that you have 2 EM declared.
Have a look at the spring-jpa docs, they'll show you how to configure the repository for how you can add specific EMF to your repos
Long story short:
You have to create custom implementation of that interface and that implementation has to contain entity manager declared as:
#PersistenceContext(unitName = "persistenceUnit1")
private EntityManager entityManager;
if you want to use persistence unit 1.
Check this out: http://docs.spring.io/spring-data/data-jpa/docs/current/reference/html/repositories.html#repositories.custom-implementations, it also has examples and example 1.17 (little bit down the page) implements interface and has entity manager in it and that entity manager is passed on to super constructor.
You may also take a look at Spring Data - JPA, customizing Repository not working, it has implementation of interface that extends JpaRepository and it also has entity manager declared in implementation. Just add unitName to #PersistenceContext annotation and try it that way.
You may not need any custom methods (so your interface can be empty) but you do need constructor that passes on entity manager and all that tinkering with extending your own interface to bypass default automatic wiring behaviour.
One of the two datasource must be defined as primary.
<bean> has a primary attribute that can be set to true or false:
<bean primary="true|false"/>
Usually in #Configuration the #Primary annotation is placed to:
EntityManager
DataSource
TransactionManager
So you can try to add primary="true"
to the following beans:
dataSource1
transactionManager1
entityManagerFactory1

how to get transaction supporting proxy from spring application context?

i need to use bean from spring application context not in a spring managed bean, so i do next: annotate bean with #Service annotation, so instance of bean created during spring loading.
<bean id="customRevisionListener" class="ru.csbi.registry.services.impl.envers.CustomRevisionListener" />
This instance is ApplicationContextAware, so application context is injected in this bean instance and i save it to static variable:
#Service
public class CustomRevisionListener implements EntityTrackingRevisionListener, ApplicationContextAware {
private static ApplicationContext applicationContext;
private ModelInformationService modelInformationService;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
CustomRevisionListener.applicationContext = applicationContext;
}
private ModelInformationService getModelInformationService() {
if (modelInformationService == null) {
modelInformationService = applicationContext.getBean(ModelInformationService.class);
}
// TransactionProxyFactoryBean
return modelInformationService;
}
After that another instance of CustomRevisionListener created in not spring context(hibernate envers context). Here i use static variable to receive spring applicationContext
after that i'm getting beans from application context:
private ModelInformationService getModelInformationService() {
if (modelInformationService == null) {
modelInformationService = applicationContext.getBean(ModelInformationService.class);
}
the problem is that this bean has all #Autowired properties injected correctly:
#Service
public class ModelInformationServiceImpl implements ModelInformationService {
#Autowired
private EntityChangeService entityChangeService; // injected correctly
#Autowired
private PropertyService propertyService; // injected correctly
#Autowired
private ru.csbi.registry.services.reflection.HibernateDomainService hibernateService; // injected correctly
, but they are simple instances of java classes not Proxies supporting #Transactional annotation, which they are for my regular spring code:
getModelInformationService().getClass().getName() is "ru.csbi.registry.services.impl.envers.ModelInformationServiceImpl"
and must be something like
$Proxy71
How to get transaction supporting proxies, which spring genereates for example when injecting beans in #Controller, in bean not managed by spring?
i'm using next spring config:
<bean id="dataSource" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
<constructor-arg ref="lazyConnectionDataSourceProxy"/>
</bean>
<bean id="lazyConnectionDataSourceProxy" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
<property name="targetDataSource">
<ref local="dataSourceTarget" />
</property>
</bean>
<bean id="dataSourceTarget" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${ds.driver}" />
<property name="url" value="${ds.url}" />
<property name="username" value="${ds.user}" />
<property name="password" value="${ds.password}" />
<property name="initialSize" value="${ds.initialSize}" />
<property name="maxActive" value="${ds.maxActive}" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<!--property name="entityInterceptor">
<bean class="ru.csbi.registry.utils.audit.AuditLogInterceptor">
<property name="sessionFactory" ref="auditSessionFactory" />
</bean>
</property-->
<property name="dataSource" ref="dataSource" />
<property name="lobHandler" ref="oracleLobHandler" />
<property name="packagesToScan" value="ru.csbi.registry.domain" />
<property name="hibernateProperties">
<bean id="hibernatePropertiesFactoryBean" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="locations">
<list>
<value>file:${realtyregistry.settings.path}/hibernate-config.properties</value>
</list>
</property>
</bean>
</property>
<property name="eventListeners">
<map>
<entry key="post-insert" value-ref="auditEventListener" />
<entry key="post-update" value-ref="auditEventListener" />
<entry key="post-delete" value-ref="auditEventListener" />
<entry key="pre-collection-update" value-ref="auditEventListener" />
<entry key="pre-collection-remove" value-ref="auditEventListener" />
<entry key="post-collection-recreate" value-ref="auditEventListener" />
</map>
</property>
</bean>
<bean id="auditEventListener" class="org.hibernate.envers.event.AuditEventListener" />
<bean id="persistenceManagerHibernate" class="ru.csbi.registry.utils.PersistenceManagerHibernate">
<property name="sessionFactory" ref="sessionFactory" />
</bean>

Spring and Mybatis multiple data sources setup

My applications uses Spring3+MyBatis3. I'm trying to setup multiple data source for it. Setup looks like:
<!-- db1 setup-->
<bean id="db1SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"
p:configLocation="WEB-INF/mybatis/sqlMapConfig.xml"
p:dataSource-ref="db1DataSource" />
<bean id="db1SqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg ref="db1SqlSessionFactory"/>
</bean>
<!-- db2 setup -->
<bean id="db2SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"
p:configLocation="WEB-INF/mybatis/sqlMapConfig.xml"
p:dataSource-ref="db2DataSource" />
<bean id="db2SqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg ref="db2SqlSessionFactory"/>
</bean>
In the logs, I've found this message:
No unique bean of type [org.apache.ibatis.session.SqlSessionFactory] is defined: expected single matching bean but found 2: [db1SqlSessionFactory, db2SqlSessionFactory]
I googled and looked into mybatis manuals but couldn't find way how to setup multiple data sources with mybatis.
Any ideas?
also solved ! just reference your factory bean in MapperScannerConfigurer : sqlSessionFactoryBeanName
First data source >>>>>>>
<bean id="dataSource1" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<bean id="sqlSessionFactory1" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource1"/>
</bean>
<bean id="MapperScannerConfigurer1" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.package.p1"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory1"/>
</bean>
Second data source >>>>>>
<bean id="dataSource2" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<bean id="sqlSessionFactory2" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource2"/>
</bean>
<bean id="MapperScannerConfigurer1" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.package.p2"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory2"/>
</bean>
solved, the problem was that I must specify directly reference to sqlSessionFactory
<bean id="myDao" class="org.mybatis.spring.mapper.MapperFactoryBean"
p:sqlSessionTemplate-ref="db1SqlSessionTemplate"
p:mapperInterface="my.project.domain.dao.MyDao"
p:sqlSessionFactory-ref="db1SqlSessionFactory"/>
In a DAO implementation use SqlSessionTemplate instead of SqlSessionDaoSupport. Inject bean db1SqlSessionTemplate or db2SqlSessionTemplate.
#Repository
public class TestDaoImpl implements TestDao{
#Autowired
private SqlSession db1SqlSessionTemplate;
...
db1SqlSessionTemplate.selectList("testSelect");
...
}
When extending SqlSessionDaoSupport the context Spring does not know that you use SqlSession.

Resources