how to convert xml notation to annotation based notation : Spring - Java - java

I have following xml configuration in my spring context xml, I have used annotation based approach very less and unable to figure out how to represent following using annotation, need help.
<bean id="myPolicyAdmin" class="org.springframework.security.oauth2.client.OAuth2RestTemplate">
<constructor-arg>
<bean class="org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordResourceDetails">
<property name="accessTokenUri" value="${accessTokenEndpointUrl}" />
<property name="clientId" value="${clientId}" />
<property name="clientSecret" value="${clientSecret}" />
<property name="username" value="${policyAdminUserName}" />
<property name="password" value="${policyAdminUserPassword}" />
</bean>
</constructor-arg>
</bean>
In my java class(Policy manager) it is referred as following, I am actually referring a sample and trying to convert it all annotation baesed.
#Autowired
#Qualifier("myPolicyAdmin")
private OAuth2RestTemplate myPolicyAdminTemplate;
EDIT:
I tried creating a bean for org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordResourceDetails but not sure how to set its properties and how to access it as constructor args to myPolicyAdminTemplate

You can configure the same beans using JavaConfig as follows:
#Component
#Configuration
public class AppConfig
{
#Value("${accessTokenEndpointUrl}") String accessTokenUri;
#Value("${clientId}") String clientId;
#Value("${clientSecret}") String clientSecret;
#Value("${policyAdminUserName}") String username;
#Value("${policyAdminUserPassword}") String password;
#Bean
public OAuth2RestTemplate myPolicyAdmin(ResourceOwnerPasswordResourceDetails details)
{
return new OAuth2RestTemplate(details);
}
#Bean
public ResourceOwnerPasswordResourceDetails resourceOwnerPasswordResourceDetails()
{
ResourceOwnerPasswordResourceDetails bean = new ResourceOwnerPasswordResourceDetails();
bean.setAccessTokenUri(accessTokenUri);
bean.setClientId(clientId);
bean.setClientSecret(clientSecret);
bean.setUsername(username);
bean.setPassword(password);
return bean;
}
}

To set the props of a bean you can either use #Value during construction:
How to inject a value to bean constructor using annotations
and this one:
Spring: constructor injection of primitive values (properties) with annotation based configuration
Or #Value in the variables. You could also actually use #Resource, but I wouldn't recommend it.
In your case, the constructor for the
org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordResourceDetails
Would be kinda like
#Autowired
public ResourceOwnerPasswordResourceDetails(
#Value("${accessTokenEndpointUrl}") String accessTokenUri,
#Value("${clientId}") String clientId,
#Value("${clientSecret}") String clientSecret,
#Value("${policyAdminUserName}") String username,
#Value("${policyAdminUserPassword}") String password
)

I shall give you a XML configuration with it anotation based config equivalent respectively, so that you will easily see how to change your bean from xml to java and vice-versa
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
<context:component-scan base-package="com.mycompany.backendhibernatejpa.controller" />
<mvc:annotation-driven />
<bean id="iAbonneDao" class="com.mycompany.backendhibernatejpa.daoImpl.AbonneDaoImpl"/>
<bean id="iAbonneService" class="com.mycompany.backendhibernatejpa.serviceImpl.AbonneServiceImpl"/>
<!-- couche de persistance JPA -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
<property name="generateDdl" value="true" />
<property name="showSql" value="true" />
</bean>
</property>
<property name="loadTimeWeaver">
<bean
class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
</property>
</bean>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations" value="classpath:bd.properties"/>
</bean>
<!-- la source de donnéees DBCP -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" >
<property name="driverClassName" value="${bd.driver}" />
<property name="url" value="${bd.url}" />
<property name="username" value="${bd.username}" />
<property name="password" value="${bd.password}" />
</bean>
<!-- le gestionnaire de transactions -->
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<!-- traduction des exceptions -->
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
<!-- annotations de persistance -->
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
</beans>
this file is named springrest-sevlet. actually you can give the name you want followed by "-servlet" and mention that name in the file web.xml
<web-app>
<display-name>Gescable</display-name>
<servlet>
<servlet-name>springrest</servlet-name>
<servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springrest</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
the two files should be place in the folder "WEB-INF".
Now the equivalent with anotation based config
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.mycompany.backendhibernatejpaannotation.configuration;
import com.mycompany.backendhibernatejpaannotation.daoImpl.AbonneDaoImpl;
import com.mycompany.backendhibernatejpaannotation.daoInterface.IAbonneDao;
import com.mycompany.backendhibernatejpaannotation.serviceImpl.AbonneServiceImpl;
import com.mycompany.backendhibernatejpaannotation.serviceInterface.IAbonneService;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
/**
*
* #author vivien saa
*/
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.mycompany.backendhibernatejpaannotation")
public class RestConfiguration {
#Bean
public IAbonneDao iAbonneDao() {
return new AbonneDaoImpl();
}
#Bean
public IAbonneService iAbonneService() {
return new AbonneServiceImpl();
}
// #Bean
// public PropertyPlaceholderConfigurer placeholderConfigurer() {
// PropertyPlaceholderConfigurer placeholderConfigurer = new PropertyPlaceholderConfigurer();
// placeholderConfigurer.setLocations("classpath:bd.properties");
// return placeholderConfigurer;
// }
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/gescable");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
#Bean
public HibernateJpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
jpaVendorAdapter.setDatabasePlatform("org.hibernate.dialect.MySQL5InnoDBDialect");
jpaVendorAdapter.setGenerateDdl(true);
jpaVendorAdapter.setShowSql(true);
return jpaVendorAdapter;
}
#Bean
public InstrumentationLoadTimeWeaver loadTimeWeaver() {
InstrumentationLoadTimeWeaver loadTimeWeaver = new InstrumentationLoadTimeWeaver();
return loadTimeWeaver;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
entityManagerFactory.setDataSource(dataSource());
entityManagerFactory.setJpaVendorAdapter(jpaVendorAdapter());
entityManagerFactory.setLoadTimeWeaver(loadTimeWeaver());
return entityManagerFactory;
}
#Bean
public JpaTransactionManager jpaTransactionManager() {
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
jpaTransactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return jpaTransactionManager;
}
#Bean
public PersistenceExceptionTranslationPostPro`enter code here`cessor persistenceExceptionTranslationPostProcessor() {
return new PersistenceExceptionTranslationPostProcessor();
}
#Bean
public PersistenceAnnotationBeanPostProcessor persistenceAnnotationBeanPostProcessor() {
return new PersistenceAnnotationBeanPostProcessor();
}
}
this file must be accompanied by this one
package com.mycompany.backendhibernatejpaannotation.configuration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
/**
*
* #author vivien saa
*/
public class Initializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{RestConfiguration.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}

Related

#Transactional annotation in Spring

I have written the below code to implment the transaction management of spring using #transactional annotation. I still feel some changes are required
in my DAO layer. May I know what changes are required . Thanks in advance
#Controller
public class RestController {
#Autowired
DataServices dataServices;
#RequestMapping(value = "/v1/dist_list/{emailId}/members", method = RequestMethod.GET)
public #ResponseBody String getDistributionListMember(#PathVariable String emailId) throws Exception, SpringException {
String retStatus = null;
retStatus = dataServices.getDistributionListMember(emailId, callerId);
]
}
}
DataServices.java
package com.uniteid.services;
import com.uniteid.model.AIWSuser;
public interface DataServices {
public String getDistributionListMember(final String emailId, final String callerID) throws Exception;
}
Below is my service layer where I added the trasactional attribute
package com.uniteid.services;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.uniteid.dao.DataDao;
import com.uniteid.model.AIWSuser;
#Service("dataService")
public class DataServicesImpl implements DataServices {
#Autowired
DataDao dataDao;
#Transactional
public String getDistributionListMember(String emailId, String callerID)
throws Exception {
return dataDao.getDistributionListMember(emailId, callerID);
}
}
Below is my spring-config file
<?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"
xmlns:util="http://www.springframework.org/schema/util" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"
xmlns:tx="http://www.springframework.org/schema/tx">
<context:component-scan base-package="com.uniteid.controller" />
<mvc:annotation-driven
content-negotiation-manager="contentNegociationManager" />
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:uniteidrest.properties" />
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url">
<value>${eidms.url}</value>
</property>
<property name="username">
<value>${eidms.username}</value>
</property>
<property name="password">
<value>${eidms.password}</value>
</property>
</bean>
<!-- <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"
/> <property name="url" value="jdbc:oracle:thin:#nyvm0467.ptc.un.org:1521:EIDMSUAT"
/> <property name="username" value="DBO_EIDMSUAT" /> <property name="password"
value="NewPassDBO_EIDMSUAT" /> </bean> -->
<bean id="contentNegociationManager"
class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="defaultContentType" value="application/json" />
<property name="ignoreAcceptHeader" value="true" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>com.uniteid.model.User</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.connection.pool_size">10</prop>
</props>
</property>
</bean>
<bean id="txManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="persistenceExceptionTranslationPostProcessor"
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
<bean id="dataDao" class="com.uniteid.dao.DataDaoImpl"></bean>
<bean id="dataServices" class="com.uniteid.services.DataServicesImpl"></bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>
It still feel I have not implemented the Transactional management properly in the below code. May I know what part of the code can be removed for me to implement it
package com.uniteid.dao;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Types;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import org.apache.log4j.Logger;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.jdbc.Work;
import org.springframework.beans.factory.annotation.Autowired;
import com.uniteid.controller.RestController;
import com.uniteid.model.AIWSuser;
import com.uniteid.model.User;
public class DataDaoImpl implements DataDao
{
#Autowired
\
SessionFactory sessionFactory;
Session session = null;
Transaction tx = null;
static final Logger logger = Logger.getLogger(DataDaoImpl.class);
public String getDistributionListMember(final String emailId, final String callerID) throws Exception {
session = sessionFactory.openSession();
tx = session.beginTransaction();
final String[] returnVal2 = { "" };
session.doWork(new Work() {
public void execute(Connection connection) throws SQLException {
CallableStatement stmt = null;
String returnVal = "";
stmt = connection.prepareCall("{?=call WS_Distributionlistmember(?,?)}");
stmt.registerOutParameter(1, Types.VARCHAR);
stmt.setString(2, emailId);
stmt.setString(3, callerID);
stmt.execute();
returnVal = stmt.getString(1);
logger.info("RETURN VALUE in getDistributionListMember method :::::: " + returnVal);
returnVal2[0] = returnVal;
logger.info("Return Value " + returnVal);
stmt.close();
}
});
tx.commit();
session.close();
return returnVal2[0];
}
}
Your code:
public String getDistributionListMember(final String emailId, final String callerID) throws Exception {
session = sessionFactory.openSession();//This is bad
tx = session.beginTransaction();//This is bad
tx.commit();//This is bad
session.close();//This is bad
Correct should be:
public String getDistributionListMember(final String emailId, final String callerID) throws Exception {
session = sessionFactory.getCurrentSession();//good way
It is because you told spring to autowired sessionFactory and from now on spring is managing your hibernate session not you. So getCurrentSession() is correct way.
#M. Deinum Thanks to point it out.
Remove bean declaration for bean id transactionManager and set txManager instead of transactionManager in transaction-manager value. As you are using hibernate with spring so HibernateTransactionManager should be used instead of DatabaseTransactionManager to define transaction boundary. DatabaseTransactionManager is used when you directly interact with data source without using any ORM or JPA framework.
In your service class define transaction boundary for method as below annotation
#Transactional(readOnly = true, propagation = Propagation.SUPPORTS)

Spring JPA Config IllegalArgumentException: No persistence unit with name found

I am having a weird issue I'm not able to wrap my head around. I have used JPA/Hibernate is Spring before with NO persistence.xml file, Spring handled everything. I'm working on a new project and this time I decided to go all Java Config. I am having some issues with my PersistenceConfig.java, it keeps saying it can't find a persistence unit. If I comment out the line the sets the PersistenceUnitName then it complains IllegalStateException: No persistence units parsed from {classpath*:META-INF/persistence.xml}.
I don't understand why its trying to use a persistence.xml when I use Java Config and not when I use XML. Any solutions?
Here is my PersistenceConfig.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;
import org.springframework.orm.jpa.JpaDialect;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaDialect;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import java.util.Properties;
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(basePackages = {"com.testapp.ots.repository"})
public class PersistenceConfig {
#Autowired
Environment environment;
#Bean(name = "datasource")
public DataSource dataSource() {
JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
dsLookup.setResourceRef(true);
return dsLookup.getDataSource("jdbc/postgres");
}
#Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
entityManagerFactory.setDataSource(dataSource());
entityManagerFactory.setPersistenceUnitName("postgres");
entityManagerFactory.setJpaProperties(jpaProperties());
entityManagerFactory.setJpaVendorAdapter(jpaVendorAdapter());
entityManagerFactory.setJpaDialect(jpaDialect());
return entityManagerFactory;
}
#Bean(name = "jpaVendorAdapter")
public JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setDatabasePlatform("org.hibernate.dialect.PostgreSQL9Dialect");
vendorAdapter.setGenerateDdl(true);
vendorAdapter.setShowSql(true);
return vendorAdapter;
}
#Bean(name = "jpaDialect")
public JpaDialect jpaDialect() {
return new HibernateJpaDialect();
}
#Bean(name = "transactionManager")
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager(entityManagerFactory);
jpaTransactionManager.setDataSource(dataSource());
jpaTransactionManager.setJpaDialect(jpaDialect());
return jpaTransactionManager;
}
#Bean(name = "persistenceExceptionTranslation")
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
public Properties jpaProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", environment.getProperty("hibernate.hbm2ddl.auto"));
properties.setProperty("hibernate.dialect", environment.getProperty("hibernate.dialect"));
properties.setProperty("hibernate.show_sql", environment.getProperty("hibernate.show_sql"));
properties.setProperty("hibernate.format_sql", environment.getProperty("hibernate.format_sql"));
properties.setProperty("hibernate.connection.charSet", environment.getProperty("hibernate.connection.charSet"));
properties.setProperty("hibernate.cache.use_second_level_cache", environment.getProperty("hibernate.cache.use_second_level_cache"));
properties.setProperty("hibernate.cache.use_query_cache", environment.getProperty("hibernate.cache.use_query_cache"));
properties.setProperty("hibernate.cache.use_structured_entries", environment.getProperty("hibernate.cache.use_structured_entries"));
properties.setProperty("hibernate.generate_statistics", environment.getProperty("hibernate.generate_statistics"));
return properties;
}
}
As a reference here is the XML configuration I used a few months back.
<?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"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<context:annotation-config />
<jpa:repositories base-package="net.jkratz.bloodpressure.api.repository" />
<jee:jndi-lookup jndi-name="jdbc/BloodPressureDB" id="dataSource" expected-type="javax.sql.DataSource" />
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="BPPersistenceUnit" />
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<property name="jpaDialect" ref="jpaDialect" />
<property name="packagesToScan">
<list>
<value>net.jkratz.bloodpressure.api.model</value>
</list>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
<prop key="hibernate.connection.charSet">${hibernate.connection.charSet}</prop>
</props>
</property>
</bean>
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="${jpa.vendor.database}" />
<property name="showSql" value="${jpa.vendor.showSql}"/>
<property name="generateDdl" value="${jpa.vendor.generateDdl}"/>
<property name="databasePlatform" value="${jpa.vendor.databasePlatform}"/>
</bean>
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="dataSource" ref="dataSource" />
<property name="jpaDialect" ref="jpaDialect" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>
From LocalEntityManagerFactoryBean documentation:
In case of Spring-based scanning, no persistence.xml is necessary; all
you need to do is to specify base packages to search here.
So, try change your bean entityManagerFactory to this:
#Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
entityManagerFactory.setDataSource(dataSource());
entityManagerFactory.setPersistenceUnitName("postgres");
entityManagerFactory.setJpaProperties(jpaProperties());
entityManagerFactory.setJpaVendorAdapter(jpaVendorAdapter());
entityManagerFactory.setJpaDialect(jpaDialect());
entityManagerFactory.setPackagesToScan("net.jkratz.bloodpressure.api.model");
return entityManagerFactory;
}

Mybatis Spring multiple databases Java configuration

I'm working with Spring and Mybatis and I have two databases, the configuration for the first database was relative easy, but I can't get to work the second database with Spring and transactions, here is my code
#Configuration
#ComponentScan(basePackages = {"hernandez.service", "hernandez.dao"})
#EnableTransactionManagement
#MapperScan(basePackages="hernandez.mapper" )
#Import(DbConfig2.class)
public class AppConfig {
#Bean(name = "dataSource")
public DataSource dataSource() {
DriverManagerDataSource ds = new DriverManagerDataSource("com.mysql.jdbc.Driver",
"jdbc:mysql://localhost:3306/northwind", "root", "");
return ds;
}
#Bean
public SqlSessionFactoryBean sqlSessionFactory() {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource());
return factoryBean;
}
#Bean(name = "transactionManager")
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
}
#Configuration
#MapperScan("loli.mapper" )
public class DbConfig2 {
#Bean(name = "dataSource_2")
public DataSource dataSource2() {
DriverManagerDataSource ds = new DriverManagerDataSource("com.mysql.jdbc.Driver",
"jdbc:mysql://localhost:3306/dmsolut_dmsms", "root", "");
return ds;
}
#Bean
public SqlSessionFactory sqlSessionFactory2() throws Exception{
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource2());
return factoryBean.getObject();
}
#Bean(name = "transactionManager_2")
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource2());
}
}
Is there a way to get this working with pure Spring Java configuration or at least with some XML? There's no official documentation to get two databases working in the Mybatis-Spring project
Multi datasources with mybatis are used in my project right now. This is an Example, add to your application.xml
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
<property name="url" value="${center.connectionURL}"/>
<property name="username" value="${userName}"/>
<property name="password" value="${password}"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.xxx.dao.center"/>
<property name="sqlSessionFactoryBeanName" value="cneterSqlSessionFactory"/>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean" name="cneterSqlSessionFactory">
<property name="dataSource" ref="dataSource"></property>
<property name="mapperLocations" value="classpath*:mapperConfig/center/*.xml"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<!--center db end-->
<!--exdb-->
<bean id="dataSourceEx" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
<property name="url" value="${ex.connectionURL}"/>
<property name="username" value="${userName}"/>
<property name="password" value="${password}"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.xxx.dao.ex"/>
<property name="sqlSessionFactoryBeanName" value="exSqlSessionFactory"/>
</bean>
<bean id="sqlSessionFactoryEx" class="org.mybatis.spring.SqlSessionFactoryBean" name="exSqlSessionFactory">
<property name="dataSource" ref="dataSourceEx"></property>
<property name="mapperLocations" value="classpath*:mapperConfig/ex/*.xml"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<bean id="transactionManagerEx" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSourceEx"/>
</bean>
Add answer with java config example we use in our project:
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.JdbcType;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
#Configuration
#ComponentScan(basePackages = "com.mycompany")
#EnableTransactionManagement(proxyTargetClass = true)
public class ApplicationConfig2 {
public static final String DATA_SOURCE_NAME_1 = "jdbc/dataSource1";
public static final String DATA_SOURCE_NAME_2 = "jdbc/dataSource2";
public static final String SQL_SESSION_FACTORY_NAME_1 = "sqlSessionFactory1";
public static final String SQL_SESSION_FACTORY_NAME_2 = "sqlSessionFactory2";
public static final String MAPPERS_PACKAGE_NAME_1 = "com.mycompany.mappers.dao1";
public static final String MAPPERS_PACKAGE_NAME_2 = "com.mycompany.mappers.dao2";
#Bean
public DataSource dataSource1() {
JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
return dsLookup.getDataSource(DATA_SOURCE_NAME_1);
}
#Bean
public DataSource dataSource2() {
JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
return dsLookup.getDataSource(DATA_SOURCE_NAME_2);
}
#Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
#Bean(name = SQL_SESSION_FACTORY_NAME_1)
public SqlSessionFactory sqlSessionFactory1(DataSource dataSource1) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setTypeHandlersPackage(DateTimeTypeHandler.class.getPackage().getName());
sqlSessionFactoryBean.setDataSource(dataSource1);
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBean.getObject();
sqlSessionFactory.getConfiguration().setMapUnderscoreToCamelCase(true);
sqlSessionFactory.getConfiguration().setJdbcTypeForNull(JdbcType.NULL);
return sqlSessionFactory;
}
#Bean(name = SQL_SESSION_FACTORY_NAME_2)
public SqlSessionFactory sqlSessionFactory2(DataSource dataSource2) throws Exception {
SqlSessionFactoryBean diSqlSessionFactoryBean = new SqlSessionFactoryBean();
diSqlSessionFactoryBean.setTypeHandlersPackage(DateTimeTypeHandler.class.getPackage().getName());
diSqlSessionFactoryBean.setDataSource(dataSource2);
SqlSessionFactory sqlSessionFactory = diSqlSessionFactoryBean.getObject();
sqlSessionFactory.getConfiguration().setMapUnderscoreToCamelCase(true);
sqlSessionFactory.getConfiguration().setJdbcTypeForNull(JdbcType.NULL);
return sqlSessionFactory;
}
#Bean
public MapperScannerConfigurer mapperScannerConfigurer1() {
MapperScannerConfigurer configurer = new MapperScannerConfigurer();
configurer.setBasePackage(MAPPERS_PACKAGE_NAME_1);
configurer.setSqlSessionFactoryBeanName(SQL_SESSION_FACTORY_NAME_1);
return configurer;
}
#Bean
public MapperScannerConfigurer mapperScannerConfigurer2() {
MapperScannerConfigurer configurer = new MapperScannerConfigurer();
configurer.setBasePackage(MAPPERS_PACKAGE_NAME_2);
configurer.setSqlSessionFactoryBeanName(SQL_SESSION_FACTORY_NAME_2);
return configurer;
}
}
In my experience, you should also add #Primary to one of the DataSource beans. Otherwise it will throw NoUniqueBeanDefinitionException.
#Bean
#Primary
public DataSource dataSource1() {
JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
return dsLookup.getDataSource(DATA_SOURCE_NAME_1);
}
#Bean
public DataSource dataSource2() {
JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
return dsLookup.getDataSource(DATA_SOURCE_NAME_2);
}
You can use spring's AbstractRoutingDataSource by extending it and overriding the method determineCurrentLookupKey().
Spring Configuration
You can define separate datasource in spring configuration.
<!-- db2 data source -->
<bean id="db2DataSource" class="com.ibm.db2.jdbc.app.DB2Driver">
<property name="serverName" value="${db2.jdbc.serverName}" />
<property name="portNumber" value="${db2.jdbc.portNumber}" />
<property name="user" value="${db2.jdbc.username}" />
<property name="password" value="${db2.jdbc.password}" />
<property name="databaseName" value="${db2.jdbc.databaseName}" />
</bean>
<!-- mysql data source -->
<bean id="mysqlDataSource" class="com.mysql.jdbc.Driver">
<property name="serverName" value="${mysql.jdbc.serverName}" />
<property name="portNumber" value="${mysql.jdbc.portNumber}" />
<property name="user" value="${mysql.jdbc.username}" />
<property name="password" value="${mysql.jdbc.password}" />
<property name="databaseName" value="${mysql.jdbc.databaseName}" />
</bean>
Associate the datasource with customer:
<bean id="customer" class="com.example.Customer">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="dataSource" class="com.example.datasource.CustomerRoutingDataSource">
<property name="targetDataSources">
<map key-type="com.example.Customer">
<entry key="db2" value-ref="mysqlDataSource"/>
<entry key="mysql" value-ref="db2DataSource"/>
</map>
</property>
<property name="defaultTargetDataSource" ref="mysql"/>
</bean>
Java
package com.example;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class CustomerRoutingDataSource extends AbstractRoutingDataSource {
#Bean
CustomerContextHolder context;
#Override
protected Object determineCurrentLookupKey() {
return context.getCustomerType();
}
}
Basically, each request will have its context. You can associate datasource with request using mapped key. You can find more details here dynamic-datasource-routing
<bean id="sqlSessionFactory1" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource1" />
<property name="configLocation">
<value>classpath:com/dtcc/dao/impl/DaoSqlMapConfig_MyBatis1.xml</value>
</property>
<property name="transactionFactory">
<bean class="org.apache.ibatis.transaction.managed.ManagedTransactionFactory" />
</property>
<property name="mapperLocations" value="classpath*:com/dtcc/dao/impl/DaoEmfMyBatis.sp.xml"/>
</bean>
<bean id="sqlSession1" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory1" />
</bean>
<!-- MyBatis Changes Ends -->
<bean id="daoEmf" class="com.dtcc.dao.DaoEmfImpl">
<property name="connectionType"><ref local="com.dtcc.sharedservices.utils.resources.ConnTypes.IBM_DB2_CONNECTION" /></property>
<property name="jndiNameForLogging"><ref local="dataSourceName1" /></property>
<property name="sqlSessionTemplate"> <ref local="sqlSession1" /></property>
<property name="applicationLog"><ref local="appLog" /></property>
</bean>
As mentioned above, we need to give corresponding sessionFactory in your DaoImpl. You can not autowire SqlSessionTemplate in your DaoImpl class if you have more than one sessionFactory. Give unique name for each session factory and map it to your respective DaoImpl class.
All you have to do is just to create object for SqlSessionTemplate with Setter method in DaoImpl class and you can make your db call using sqlSessionTemplate object as below,
this.sqlSessionTemplate.selectList("ProcedureID", parameter);

spring xml based configuration from java based configuration

I am doing sample chat application using spring mvc and redis server by following steps from
http://blog.springsource.org/2012/05/16/spring-mvc-3-2-preview-chat-sample/
the example given there is by spring java based configurations. I want to do with xml based configurations. But it is not working for me.
I am getting the issues by converting following configuration class
package org.springframework.samples.async.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.samples.async.chat.ChatController;
#Configuration
#PropertySource("classpath:redis.properties")
public class RootConfig {
#Autowired
Environment env;
#Autowired
ChatController chatController;
#Bean
public RedisConnectionFactory redisConnectionFactory() {
JedisConnectionFactory cf = new JedisConnectionFactory();
cf.setHostName(this.env.getProperty("redis.host"));
cf.setPort(this.env.getProperty("redis.port", int.class));
cf.setPassword(this.env.getProperty("redis.password"));
return cf;
}
#Bean
public StringRedisTemplate redisTemplate() {
return new StringRedisTemplate(redisConnectionFactory());
}
#Bean
public RedisMessageListenerContainer redisMessageListenerContainer() {
RedisMessageListenerContainer mlc = new RedisMessageListenerContainer();
mlc.setConnectionFactory(redisConnectionFactory());
mlc.addMessageListener(this.chatController , new PatternTopic("chat"));
return mlc;
}
}
The following is the Xml based configuration i am trying to use instead of above java based configuration.
<bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
p:host-name="localhost" p:port="9994" p:password=""/>
<bean id="messageListener" class="org.springframework.data.redis.listener.adapter.MessageListenerAdapter">
<constructor-arg>
<bean class="org.springframework.samples.async.chat.ChatController"/>
</constructor-arg>
</bean>
<bean id="redisMessageListenerContainer" class="org.springframework.data.redis.listener.RedisMessageListenerContainer">
<property name="connectionFactory" ref="redisConnectionFactory"/>
<property name="messageListeners">s
<map>
<entry key-ref="messageListener">
<bean class="org.springframework.data.redis.listener.PatternTopic">
<constructor-arg value="chat"/>
</bean>
</entry>
</map>
</property>
</bean>
The exception i am getting is
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'messageListener' defined in ServletContext resource [/WEB-INF/spring/mvc-config.xml]: Cannot create inner bean 'org.springframework.samples.async.chat.ChatController#74b70648' of type [org.springframework.samples.async.chat.ChatController] while setting constructor argument; nested exception is org.springframework.beans.factory.CannotLoadBeanClassException: Cannot find class [org.springframework.samples.async.chat.ChatController] for bean with name 'org.springframework.samples.async.chat.ChatController#74b70648' defined in ServletContext resource [/WEB-INF/spring/mvc-config.xml]; nested exception is java.lang.ClassNotFoundException: org.springframework.samples.async.chat.ChatController
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:282)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:121)
at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:629)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:148)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1049)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:953)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:490)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:626)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:652)
at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:600)
at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:666)
at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:519)
at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:460)
at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136)
at javax.servlet.GenericServlet.init(GenericServlet.java:160)
at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1280)
at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1193)
at org.apache.catalina.core.StandardWrapper.allocate(StandardWrapper.java:865)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:136)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at jav
a.lang.Thread.run(Thread.java:662)
ChatController.java
package org.springframework.samples.async.chat;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.async.DeferredResult;
#Controller
#RequestMapping("/mvc/chat")
public class ChatController implements MessageListener {
private final Map<DeferredResult<List<String>>, Integer> chatRequests =
new ConcurrentHashMap<DeferredResult<List<String>>, Integer>();
private final ChatRepository chatRepository;
#Autowired
public ChatController(ChatRepository chatRepository) {
this.chatRepository = chatRepository;
}
#RequestMapping(method=RequestMethod.GET, produces="application/json")
#ResponseBody
public DeferredResult<List<String>> getMessages(#RequestParam int messageIndex) {
final DeferredResult<List<String>> deferredResult = new DeferredResult<List<String>>(null, Collections.emptyList());
this.chatRequests.put(deferredResult, messageIndex);
deferredResult.onCompletion(new Runnable() {
#Override
public void run() {
chatRequests.remove(deferredResult);
}
});
List<String> messages = this.chatRepository.getMessages(messageIndex);
if (!messages.isEmpty()) {
deferredResult.setResult(messages);
}
return deferredResult;
}
#RequestMapping(method=RequestMethod.POST)
#ResponseBody
public void postMessage(#RequestParam String message) {
this.chatRepository.addMessage(message);
}
// Redis MessageListener contract
#Override
public void onMessage(Message message, byte[] pattern) {
for (Entry<DeferredResult<List<String>>, Integer> entry : this.chatRequests.entrySet()) {
List<String> messages = this.chatRepository.getMessages(entry.getValue());
entry.getKey().setResult(messages);
}
}
}
The complete mvc-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
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-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven>
<mvc:async-support default-timeout="30000" />
</mvc:annotation-driven>
<mvc:view-controller path="/" view-name="chat"/>
<mvc:resources mapping="/resources/**" location="resources"/>
<context:component-scan base-package="org.springframework.samples.async.chat" />
<bean id="templateResolver" class="org.thymeleaf.templateresolver.ServletContextTemplateResolver">
<property name="prefix" value="/WEB-INF/templates/" />
<property name="suffix" value=".html" />
<property name="templateMode" value="HTML5" />
<property name="cacheable" value="true" />
</bean>
<bean id="templateEngine" class="org.thymeleaf.spring3.SpringTemplateEngine">
<property name="templateResolver" ref="templateResolver" />
</bean>
<bean id="viewResolver" class="org.thymeleaf.spring3.view.ThymeleafViewResolver">
<property name="templateEngine" ref="templateEngine" />
<property name="order" value="1" />
<property name="viewNames" value="*.html"/>
</bean>
<bean id="stringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate"
p:connection-factory-ref="redisConnectionFactory"/>
<bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
p:host-name="localhost" p:port="9994" p:password=""/>
<bean id="messageListener" class="org.springframework.data.redis.listener.adapter.MessageListenerAdapter">
<constructor-arg>
<bean class="org.springframework.samples.async.chat.ChatController"/>
</constructor-arg>
</bean>
<bean id="redisMessageListenerContainer" class="org.springframework.data.redis.listener.RedisMessageListenerContainer">
<property name="connectionFactory" ref="redisConnectionFactory"/>
<property name="messageListeners">
<!-- map of listeners and their associated topics (channels or/and patterns) -->
<map>
<entry key-ref="messageListener">
<bean class="org.springframework.data.redis.listener.PatternTopic">
<constructor-arg value="chat"/>
</bean>
</entry>
</map>
</property>
</bean>
</beans>
Please help me out.
I think the issue is that you are trying to do some sort of autowire by class thing in your xml with this portion (I am assuming):
<bean id="messageListener" class="org.springframework.data.redis.listener.adapter.MessageListenerAdapter">
<constructor-arg>
<bean class="org.springframework.samples.async.chat.ChatController"/>
</constructor-arg>
</bean>
But that is not how the xml configuration works. What the xml is doing here is trying to create a new instance of the ChatController and use it as a constructor argument to the MessageListenerAdapter. Obviously this doesn't work because your ChatController has no 0 arg constructors. What you want to do instead is reference your existing ChatController (which is marked as an #Controller and will therefore be automatically picked up by your component-scan) in the constructor argument. Something like this:
<bean id="messageListener" class="org.springframework.data.redis.listener.adapter.MessageListenerAdapter">
<constructor-arg>
<ref bean="chatController"/>
</constructor-arg>
</bean>
The bean being referenced by 'chatController' is your component-scanned ChatController (it is the default bean name when none is provided via the stereotype annotations or the #Qualifier annotation).

NoSuchBeanDefinitionException while using #Configuration

I have weird situation.
I tried to create new bean while using the #Configuration an #Bean this way:
package com.spring.beans.ParkingCar;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class CarMaker
{
#Bean
public CarBean createNewCar()
{
CarBean carBean=new CarBean();
return carBean;
}
}
package com.spring.beans.ParkingCar;
import org.apache.log4j.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class CarBean
{
private int x = 3;
static Logger logger = Logger.getLogger(CarBean.class);
public void driveCar()
{
logger.debug("I am driving my car" + x);
}
}
and then my test class looks like this:
public static void execute()
{
try
{
PropertyConfigurator.configure("log4j.properties");
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
CarMaker carMaker = (CarMaker) context.getBean("carMaker");
CarBean carBean = carMaker.createNewCar();
carBean.driveCar();
}
catch (Throwable e)
{
logger.error(e);
}
}
my applicationContext.xml looks like this:
<?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:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" 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.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!-- Must for auto wiring
<context:annotation-config />
-->
<context:component-scan
base-package="com.spring.beans.ParkingCar">
</context:component-scan>
<aop:aspectj-autoproxy />
<bean id="Spring3HelloWorldBean" class="com.spring.aspect.Spring3HelloWorld">
<property name="myname" value="idan" />
</bean>
<bean id="SecurityAspect" class="com.spring.aspect.SecurityAspect">
</bean>
<bean id="CalculateStrategyBean" class="com.spring.beans.calculator.CalculateStrategyBean">
<constructor-arg value="plus" />
</bean>
<bean id="CalculatorBean" class="com.spring.beans.calculator.CalculatorBean">
<constructor-arg ref="CalculateStrategyBean" />
<constructor-arg ref="CalculateNumbersHolderBean" />
</bean>
<bean id="CalculateNumbersHolderBean" class="com.spring.beans.calculator.CalculateNumbersHolderBean">
<constructor-arg value="10" />
<constructor-arg value="20" />
</bean>
<bean id="lisenceDrive" class="com.spring.beans.ParkingCar.LisenceDrive"
p:carLisenceNum="333" p:isValidateCar="true" />
<bean id="AmbulancelisenceDrive" class="com.spring.beans.ParkingCar.LisenceDrive"
p:carLisenceNum="999" p:isValidateCar="false" />
<bean id="TransitlisenceDrive" class="com.spring.beans.ParkingCar.LisenceDrive"
p:carLisenceNum="111" p:isValidateCar="false" />
<bean id="TransitVechileDetails" class="com.spring.beans.ParkingCar.VechileDetails"
p:modelName="Transit-AS" p:numOfWheels="4" p:year="1992" />
<!-- Wiring without annotations-->
<!--
<bean id="Ambulance"
class="com.spring.beans.ParkingCar.FourWheelsVechile"
p:modelName="GMC" p:numOfWheels="4" p:year="1997"
p:lisenceDrive-ref="AmbulancelisenceDrive" /> <bean id="Bike"
class="com.spring.beans.ParkingCar.TwoWheelsVechile" autowire="byName"
p:modelName="T-BIRD" p:numOfWheels="2" p:year="2012" /> <bean
id="Transit" class="com.spring.beans.ParkingCar.FourWheelsVechile"
p:lisenceDrive-ref="TransitlisenceDrive" autowire="constructor">
-->
<bean id="Ambulance" class="com.spring.beans.ParkingCar.FourWheelsVechile"
p:modelName="GMC" p:numOfWheels="4" p:year="1997" p:lisenceDrive-ref="AmbulancelisenceDrive" />
<!-- Wiring with annotations
<bean id="Bike" class="com.spring.beans.ParkingCar.TwoWheelsVechile"
autowire="byName" p:modelName="T-BIRD" p:numOfWheels="2" p:year="2012" />
<bean id="Transit" class="com.spring.beans.ParkingCar.FourWheelsVechile"
p:lisenceDrive-ref="TransitlisenceDrive">
</bean>
-->
</beans>
Now when I ran it on MyEclipse thru main it worked just fine. but when I uploaded it to my stand alone application which is running on Linux I got:
2012-07-01 14:11:21,152 com.spring.test.Spring3HelloWorldTest [ERROR] org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'carMaker' is defined
Any idea why it didn't work there?
Thanks.
#Configuration indicates that a class declares one or more #Bean methods while #Bean creates a new bean which have same name as the name of the method annotated with #Bean .
In your code sample bean with name createNewCar will be created as method createNewCar() method is annotated by #Bean.
Try this
CarBean carBean = (CarBean) context.getBean("createNewCar");
carBean.driveCar();
Few things to look at
Why to annotate class CarBean as #Configuration? It dont contain any bean defination ie. method with #Bean annotation.
Why to invoke createNewCar() method as it is already annotated with #Bean? (Let Spring do its work)
Check this link it will help you to get familiar with #Configuration and #Bean annotation.

Categories