Embedded Redis tries to connect to real Redis server, resulting in an exception - spring

I am trying to use embedded redis for my dev spring profile (I also have a cloud profile that connects to a real redis).
However, it seems that my embedded redis configuration tries to connect to the real redis.
Here is the error I get when I run the dev profile:
Caused by: redis.clients.jedis.exceptions.JedisDataException: NOAUTH Authentication required.
at redis.clients.jedis.Protocol.processError(Protocol.java:113)
at redis.clients.jedis.Protocol.process(Protocol.java:131)
at redis.clients.jedis.Protocol.read(Protocol.java:200)
at redis.clients.jedis.Connection.readProtocolWithCheckingBroken(Connection.java:285)
at redis.clients.jedis.Connection.getBinaryMultiBulkReply(Connection.java:221)
at redis.clients.jedis.Connection.getMultiBulkReply(Connection.java:214)
at redis.clients.jedis.Jedis.configGet(Jedis.java:2758)
at org.springframework.data.redis.connection.jedis.JedisConnection.getConfig(JedisConnection.java:554)
... 19 more
The JedisDataException NOAUTH is because I have activated authentication on the real Redis server and it tries to connect to the real server...
Here is my Spring configuration:
#Configuration
public class RedisConfiguration {
#Autowired
private RedisConnectionFactory redisConnectionFactory;
#Bean
public RedisTemplate<String, String> redisTemplate() {
RedisTemplate<String, String> redisTemplate = new RedisTemplate<String, String>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
return redisTemplate;
}
}
"dev" and "test" configuration:
#Configuration
#EnableRedisHttpSession
#Profile({ Profiles.DEV, Profiles.TEST })
public class RedisDevTestSessionConfiguration {
#Bean
public RedisConnectionFactory redisConnectionFactory() {
return new JedisConnectionFactory();
}
#Bean
public RedisServerBean redisServer() {
return new RedisServerBean();
}
class RedisServerBean implements InitializingBean, DisposableBean {
private RedisServer redisServer;
public void afterPropertiesSet() throws Exception {
redisServer = new RedisServer(Protocol.DEFAULT_PORT);
redisServer.start();
}
public void destroy() throws Exception {
if (redisServer != null) {
redisServer.stop();
}
}
}
}
Cloud configuration:
#Configuration
#EnableRedisHttpSession
#Profile(Profiles.CLOUD)
public class RedisCloudSessionConfiguration extends AbstractCloudConfig {
#Bean
public RedisConnectionFactory redisConnectionFactory() {
PoolConfig poolConfig = new PoolConfig(10, 200);// TODO: configure!
return connectionFactory().redisConnectionFactory("REDISCLOUD", new PooledServiceConnectorConfig(poolConfig));
}
Here is my dependency:
compile("redis.embedded:embedded-redis:0.4")
Profiles:
public final class Profiles {
public static final String CLOUD = "cloud";
public static final String TEST = "test";
public static final String DEV = "dev";
public static final String CAPACITY_TEST = "capacity-test";
}
edit:
Here is what the exception I get and the corresponding configuration is given below:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'redisServer' defined in class path resource [com/bignibou/configuration/session/EmbeddedRedisConfiguration.class]: Invocation of init method failed; nested exception is java.lang.RuntimeException: Can't start redis server. Check logs for details.
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:755)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:686)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:957)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:946)
at com.bignibou.Application.main(Application.java:22)
Caused by: java.lang.RuntimeException: Can't start redis server. Check logs for details.
at redis.embedded.AbstractRedisInstance.awaitRedisServerReady(AbstractRedisInstance.java:66)
at redis.embedded.AbstractRedisInstance.start(AbstractRedisInstance.java:37)
at redis.embedded.RedisServer.start(RedisServer.java:11)
at com.bignibou.configuration.session.EmbeddedRedisConfiguration$RedisServerBean.afterPropertiesSet(EmbeddedRedisConfiguration.java:26)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1633)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1570)
... 15 more
Here is my edited redis configuration:
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import redis.clients.jedis.Protocol;
import redis.embedded.RedisServer;
#Configuration
#Profile({ "dev" })
public class EmbeddedRedisConfiguration {
#Bean
public RedisServerBean redisServer() {
return new RedisServerBean();
}
class RedisServerBean implements InitializingBean, DisposableBean {
private RedisServer redisServer;
public void afterPropertiesSet() throws Exception {
redisServer = new RedisServer(Protocol.DEFAULT_PORT);
redisServer.start();
}
public void destroy() throws Exception {
if (redisServer != null) {
redisServer.stop();
}
}
}
}

Related

How to do integration testing for custom mongo repository?

These are the following configuration that I have done in my project.
#Configuration
public class AppMongoConfig {
#Autowired private MongoDbFactory mongoDbFactory;
#Autowired private MongoMappingContext mongoMappingContext;
#Bean
public MappingMongoConverter mappingMongoConverter() {
DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory);
MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, mongoMappingContext);
converter.setTypeMapper(new DefaultMongoTypeMapper(null));
return converter;
}
}
#Configuration
#RequiredArgsConstructor
#EnableConfigurationProperties(MultipleMongoProperties.class)
public class MultipleMongoConfig {
private final MultipleMongoProperties mongoProperties;
#Primary
#Bean(name = "primaryMongoTemplate")
public MongoTemplate primaryMongoTemplate() throws Exception {
return new MongoTemplate(primaryFactory(this.mongoProperties.getPrimary()));
}
#Bean(name = "secondaryMongoTemplate")
public MongoTemplate secondaryMongoTemplate() throws Exception {
return new MongoTemplate(secondaryFactory(this.mongoProperties.getSecondary()));
}
#Bean
#Primary
public MongoDbFactory primaryFactory(final MongoProperties mongo) throws Exception {
return new SimpleMongoDbFactory(new MongoClientURI(mongo.getUri()));
}
#Bean
public MongoDbFactory secondaryFactory(final MongoProperties mongo) throws Exception {
return new SimpleMongoDbFactory(new MongoClientURI(mongo.getUri()));
}
}
#Data
#ConfigurationProperties(prefix = "mongodb")
public class MultipleMongoProperties {
private MongoProperties primary = new MongoProperties();
private MongoProperties secondary = new MongoProperties();
}
#Configuration
#EnableMongoRepositories(
basePackages = {"com.student.repository.primary"},
mongoTemplateRef = "primaryMongoTemplate")
public class PrimaryMongoConfig {}
#Configuration
#EnableMongoRepositories(
basePackages = {"com.student.repository.secondary"},
mongoTemplateRef = "secondaryMongoTemplate")
public class SecondaryMongoConfig {}
Repository code:
public interface StudentDAO {
Student save(StudentInfo studentInfo);
}
#Repository
public class StudentDAOImpl implements StudentDAO {
#Autowired #Qualifier("primaryMongoTemplate")
private MongoTemplate mongoTemplate;
#Override public StudentInfo save(StudentInfo userWatchlist) {
return mongoTemplate.save(userWatchlist);
}
}
Integration Testing code:
#RunWith(SpringRunner.class)
#DataMongoTest(includeFilters = #Filter(Repository.class))
public class WatchListDAOImplIT {
#Autowired private StudentDAO studentDAO;
#Test
public void save() {
StudentInfo studentInfo = getStudentInfo();
StudentInfo dbUserWatchlist = watchListDAO.save(studentInfo);
Assert.assertEquals(studentInfo.getId(), dbUserWatchlist.getId());
}
private StudentInfo getStudentInfo() {
StudentInfo studentInfo = new StudentInfo();
studentInfo.setId(9999999l);
return studentInfo;
}
}
Which is giving me following error:-
java.lang.IllegalStateException: Failed to load ApplicationContext
at
org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:125)
at
org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:108)
at
org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:
: org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'appMongoConfig': Unsatisfied dependency
expressed through field 'mongoDbFactory'; nested exception is
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'primaryFactory' defined in class path
resource [.../config/mongo/MultipleMongoConfig.class]: Unsatisfied
dependency expressed through method 'primaryFactory' parameter 0;
nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type
'org.springframework.boot.autoconfigure.mongo.MongoProperties'
available: expected at least 1 bean which qualifies as autowire
candidate. Dependency annotations: {}
Caused by:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type
'org.springframework.boot.autoconfigure.mongo.MongoProperties'
available: expected at least 1 bean which

Unable to load application properties in springboot

I have application related properties in my spring boot application. The strange issue is sometimes the properties load without any issues but most of the times they throw an exception.
Here is my spring boot class annotated with #Configuration. Tried debugging the issue but could not find any reason for this weird behavior.
#Configuration
public class RedisConfig {
private static final Logger logger = LoggerFactory.getLogger(RedisConfig.class);
#Value("${redisurl}")
private String redisURL;
#Value("${redisport}")
private String redisPort;
#Bean
public JedisConnectionFactory redisConnectionFactory() {
logger.info("--redisURL-" + redisURL);
logger.info("--redisPort-" + redisPort);
JedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory();
redisConnectionFactory.setHostName(redisURL);
redisConnectionFactory.setPort(Integer.parseInt(redisPort));
logger.info("--connected to redis--");
return redisConnectionFactory;
}
redisurl=cst-prd-007
redisport=6379
redispassword=
Any help is appreciated.
Stacktrace:
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.boot.actuate.autoconfigure.redis.RedisHealthIndicatorConfiguration': Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'redisConfig': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'redisurl' in value "${redisurl}"
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:729)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:192)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1270)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1127)
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'redisurl' in value "${redisurl}"
at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:172)
at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:124)
at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:237)
at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:211)
at org.springframework.context.support.PropertySourcesPlaceholderConfigurer.lambda$processProperties$0(PropertySourcesPlaceholderConfigurer.java:175)
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveEmbeddedValue(AbstractBeanFactory.java:834)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1086)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1065)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:584)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:91)
at org.springframework.beans.factory.annotation.AutowiredAnnotationB
Edit:
I also tried doing this. Did not work
#Autowired
Environment env;
#Bean
public JedisConnectionFactory redisConnectionFactory() {
logger.info("--redisURL-" + redisURL);
logger.info("--redisPort-" + redisPort);
redisURL = env.getRequiredProperty("redis.url");
redisPort = env.getRequiredProperty("redis.port");
JedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory();
redisConnectionFactory.setHostName(redisURL);
redisConnectionFactory.setPort(Integer.parseInt(redisPort));
logger.info("--connected to redis--");
return redisConnectionFactory;
}
Issue solved after using the below approach
#Component
public class RedisConf {
#Value("${redis.url}")
String url;
#Value("${redis.port}")
int port;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
}
Instead of using #Value annotation, you can try using Environment from Spring Framework API.
Like this,
#Configuration
public class RedisConfig {
private static final Logger logger = LoggerFactory.getLogger(RedisConfig.class);
private String redisURL, redisPort;
#Autowired
private Environment env;
#Bean
public JedisConnectionFactory redisConnectionFactory() {
redisURL = env.getRequiredProperty("redisurl");
redisPort = env.getRequiredProperty("redisport");
JedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory();
redisConnectionFactory.setHostName(redisURL);
redisConnectionFactory.setPort(Integer.parseInt(redisPort));
logger.info("--connected to redis--");
return redisConnectionFactory;
}
The issue is solved after using the below approach
#Component
public class RedisConf {
#Value("${redis.url}")
String url;
#Value("${redis.port}")
int port;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
}

Spring Accessing configuration - AlreadyBuiltException when setting variable using #Value

I am implementing ldap authentication using Spring Security. It works when I hardcode all the ldap server information in following configuration class.
//WebSecurityConfig.java
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.formLogin();
}
#Configuration
protected static class AuthenticationConfiguration extends
GlobalAuthenticationConfigurerAdapter {
#Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource("ldap://ldap.mdanderson.edu:389/dc=mdanderson,dc=edu");
contextSource.setUserDn("cn=ris_flow,ou=service accounts,ou=institution,ou=service accounts,dc=mdanderson,dc=edu");
contextSource.setPassword("xxxyyyzzz");
contextSource.setReferral("follow");
contextSource.afterPropertiesSet();
LdapAuthenticationProviderConfigurer<AuthenticationManagerBuilder> ldapAuthenticationProviderConfigurer = auth.ldapAuthentication();
ldapAuthenticationProviderConfigurer
.userDnPatterns("cn={0},ou=institution,ou=people")
.userSearchBase("")
.contextSource(contextSource);
}
}
}
I decided to put these server information in application.properties and set the variables using #Value in my config class, so I add the following right before AuthenticationConfiguration.
#Value("${ldap.contextSource.url")
private static String url;
#Value("${ldap.contextSource.managerDn")
private static String userDn;
#Value("${ldap.contextSource.managerPass")
private static String userPass;
And replaced the lines of contextSource to:
DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource(url);
contextSource.setUserDn(userDn);
contextSource.setPassword(userPass);
However when I ran it again, the application failed to start with errors below:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'springSecurityFilterChain' defined in class path resource.......
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate....
Caused by: java.lang.IllegalArgumentException: An LDAP connection URL must be supplied.
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'springSecurityFilterChain' defined in class path resource....
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate....
Caused by: org.springframework.security.config.annotation.AlreadyBuiltException: This object has already been built
What did I do wrong?
Check this piece of code
#Value("${ldap.contextSource.url")
private static String url;
#Value("${ldap.contextSource.managerDn")
private static String userDn;
#Value("${ldap.contextSource.managerPass")
private static String userPass;
You need to close the brackets properly this way
#Value("${ldap.contextSource.url}") private static String url;
#Value("${ldap.contextSource.managerDn}") private static String userDn;
#Value("${ldap.contextSource.managerPass}") private static String userPass;
From Spring In Action Fourth Edition book:
When relying on component-scanning and autowiring to create and initialize your
application components, there’s no configuration file or class where you can specify the placeholders. Instead, you can use the #Value annotation in much the same way as you might use the #Autowired annotation.
In order to use placeholder values, you must configure either a PropertyPlaceholderConfigurer bean or a PropertySourcesPlaceholderConfigurer bean. Starting with Spring 3.1, PropertySourcesPlaceholderConfigurer is preferred because it resolves placeholders against the Spring Environment and its set of property sources.
The following #Bean method configures PropertySourcesPlaceholderConfigurer
in Java configuration:
#Bean
public
static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
EDIT: Complete example accesing properties using SPRING 4.2.5 RELEASE
Configuration Class:
#Configuration
#ComponentScan
#PropertySource("classpath:/your/package/example.properties")
// In my case, this package is stored in src/main/resources folder, which is in the classpath of the application
public class SpringPropertiesConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
Component (Bean) accessing the properties:
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
#Component
public class ComponentAccessingProperties {
#Value("${first.property}")
private String propertyOne;
#Value("${second.property}")
private String propertyTwo;
public String getPropertyOne() {
return propertyOne;
}
public String getPropertyTwo() {
return propertyTwo;
}
}
Example properties file (/your/package/example.properties):
first.property=ONE
second.property=SECOND
Test Class:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import your.package.ComponentAccessingProperties;
import your.package.SpringPropertiesConfig;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = SpringPropertiesConfig.class)
public class TestAccessingProperties {
#Autowired
private ComponentAccessingProperties componentAccesingProperties;
#Test
public void shouldNotBeNull() {
assertNotNull(componentAccesingProperties);
}
#Test
public void checkProperties() {
assertEquals("ONE", componentAccesingProperties.getPropertyOne());
assertEquals("SECOND", componentAccesingProperties.getPropertyTwo());
}
}

MongoDB and Spring JPA integration is throwing error

I am trying to integrate Spring JPA with MongoDB. My intention is to just retrieve data from mongo DB. I am getting the below error while injecting my repository.
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mongoService': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.org.coop.society.data.mongo.repositories.MaterialMasterRepository com.org.coop.security.service.MongoService.materialMasterRepository; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'materialMasterRepository': Invocation of init method failed; nested exception is java.lang.AbstractMethodError
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1210)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
My configuration snippet is given below.
TestMongoDBConfig.java
#Configuration
#EnableMongoRepositories(basePackages = {"com.abc.data.mongo.repositories"})
#ComponentScan(basePackages = "com.abc")
#PropertySource("classpath:applicationTest.properties")
public class TestMongoDBConfig extends AbstractMongoConfiguration {
#Autowired
private Environment env;
#Override
protected String getDatabaseName() {
return "retail";
}
#Override
#Bean
public MongoClient mongo() throws Exception {
MongoClient client = new MongoClient("localhost", 27017);
return client;
}
#Override
protected String getMappingBasePackage() {
return "com.abc.data.mongo.entities";
}
#Bean
public MongoTemplate mongoTemplate() throws Exception {
return new MongoTemplate(mongo(), getDatabaseName());
}
}
MaterialMaster.java in com.abc.data.mongo.entities package
#Document(collection = "materialMaster")
public class MaterialMaster {
#Id
private Long materialId;
#Field
private String name;
MaterialMasterRepository.java in com.abc.data.mongo.repositories package
public interface MaterialMasterRepository extends MongoRepository<MaterialMaster, Long> {
}
MongoService.java in com.abc.service package
#Service
public class MongoService {
#Autowired
private MaterialMasterRepository materialMasterRepository;
public void getMaterials() {
List<MaterialMaster> materials = materialMasterRepository.findAll();
System.out.println(materials);
}
}
Junit class looks like below
#RunWith(SpringJUnit4ClassRunner.class)
#ComponentScan(basePackages = "com.abc")
#ContextHierarchy({
#ContextConfiguration(classes={TestMongoDBConfig.class})
})
public class ModuleWSTest {
#Autowired
private MongoService mongoService;
#Test
public void testModule() {
mongoService.getMaterials();
}
}
I have tried all possible changes (as per my knowledge) but no luck. Any help is really appreciated.
The error message is little confusing. I was using latest spring-data-mongodb (1.8.4.RELEASE). Once I downgraded the dependency to 1.6.0.RELEASE then the above configuration started working.

Spring 4 + hibernate 4 + c3p0 : Could not obtain transaction-synchronized Session for current thread

I an trying to run simple application that uses Spring 4, Hibernate 4, and c3p0 pooling, and I keep getting this error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userDao': Invocation of init method failed; nested exception is org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:136)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:408)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1560)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:540)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:229)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:762)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:403)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:106)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4937)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5434)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:724)
Caused by: org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:134)
at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:1014)
at ggdb.components.database.dao.GenericDao.getCurrentSession(GenericDao.java:61)
at ggdb.components.database.dao.UserDao.getUser(UserDao.java:36)
at ggdb.components.database.dao.UserDao.postConstruct(UserDao.java:24)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:349)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:300)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:133)
... 23 more
Here is my configuration:
#Configuration
#EnableTransactionManagement
#PropertySource("classpath:application.properties")
public class DatabaseConfigutarion implements TransactionManagementConfigurer {
#Autowired
private Environment env;
public class PropertiesKeys {
public static final String DATABASE_HOST = "database.host";
public static final String DATABASE_PORT = "database.port";
public static final String DATABASE_USERNAME = "database.username";
public static final String DATABASE_PASSWORD = "database.password";
public static final String DATABASE_NAME = "database.database_name";
public static final String DATABASE_ADDITIONAL_CONNECTION_PROPERTIES = "database.additional.connection.properties";
public static final String HIBERNATE_DEFAULT_SCHEMA = "hibernate.default_schema";
public static final String HIBERNATE_HBM2DDL_AUTO = "hibernate.hbm2ddl.auto";
}
#Bean
public SessionFactory sessionFactory() {
String databaseUrl = String.format("jdbc:mysql://%s:%s/%s", env.getProperty(PropertiesKeys.DATABASE_HOST), env.getProperty(PropertiesKeys.DATABASE_PORT), env.getProperty(PropertiesKeys.DATABASE_NAME));
String additionnalProperties = env.getProperty(PropertiesKeys.DATABASE_ADDITIONAL_CONNECTION_PROPERTIES);
databaseUrl = ( additionnalProperties.isEmpty() ? databaseUrl : String.format("%s?%s", databaseUrl, additionnalProperties) );
org.hibernate.cfg.Configuration configuration = new org.hibernate.cfg.Configuration();
configuration.setProperty("hibernate.connection.driver_class", com.mysql.jdbc.Driver.class.getName());
configuration.setProperty("hibernate.connection.url", databaseUrl);
configuration.setProperty("hibernate.connection.username", env.getProperty(PropertiesKeys.DATABASE_USERNAME));
configuration.setProperty("hibernate.connection.password", env.getProperty(PropertiesKeys.DATABASE_PASSWORD));
configuration.setProperty("hibernate.c3p0.min_size", "5");
configuration.setProperty("hibernate.c3p0.max_size", "20");
configuration.setProperty("hibernate.c3p0.timeout", "1800");
configuration.setProperty("hibernate.c3p0.max_statements", "50");
configuration.setProperty("hibernate.current_session_context_class", org.springframework.orm.hibernate4.SpringSessionContext.class.getName());
configuration.setProperty("hibernate.dialect", org.hibernate.dialect.MySQL5InnoDBDialect.class.getName());
configuration.setProperty("hibernate.show_sql", "false");
configuration.setProperty("hibernate.format_sql", "false");
configuration.setProperty("hibernate.temp.use_jdbc_metadata_defaults", "false");
configuration.setProperty("hibernate.default_schema", env.getProperty(PropertiesKeys.HIBERNATE_DEFAULT_SCHEMA));
configuration.setProperty("hibernate.hbm2ddl.auto", env.getProperty(PropertiesKeys.HIBERNATE_HBM2DDL_AUTO));
configuration.addAnnotatedClass(ggdb.components.database.entities.User.class);
configuration.addAnnotatedClass(ggdb.components.database.entities.Role.class);
ServiceRegistry serviceRegistry = (new StandardServiceRegistryBuilder())
.applySettings(configuration.getProperties())
.build();
SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);
return sessionFactory;
}
#Bean
public HibernateTransactionManager transactionManager(){
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory());
return transactionManager;
}
#Override
public HibernateTransactionManager annotationDrivenTransactionManager() {
return transactionManager();
}
public Environment getEnv() {
return env;
}
public void setEnv(Environment env) {
this.env = env;
}
}
And code that throws error:
#Repository
public class UserDao extends GenericDao<User> {
public UserDao() {
super(User.class);
}
// TODO: this method is temporary,
// should be removed later,
#PostConstruct
#Transactional
public void postConstruct() {
User user = getUser("user");
if (user == null) {
user = new User();
user.setUsername("user");
user.setPassword("pass");
save(user);
}
}
#Transactional
public User getUser(String username) {
#SuppressWarnings("unchecked")
List<User> users = (List<User>) getCurrentSession().getNamedQuery(User.FIND_BY_USERNAME).setParameter("username", username).list();
return (users.isEmpty() ? null : users.get(0));
}
}
Extended class code:
public class GenericDao<T> {
private final Class<T> parameterClass;
#Autowired
protected SessionFactory sessionFactory;
public GenericDao(Class<T> parameterClass) {
this.parameterClass = parameterClass;
}
protected Session getSession() {
return sessionFactory.getCurrentSession();
}
public Long save(T t) {
return (Long) getSession().save(t);
}
public void delete(Long id) {
getSession().delete(id);
}
#SuppressWarnings("unchecked")
public T get(Long id) {
return (T) getSession().get(parameterClass, id);
}
public void refresh(T t) {
getSession().refresh(t);
}
#SuppressWarnings("unchecked")
public T merge(T t) {
return (T) getSession().merge(t);
}
public void update(T t) {
getSession().update(t);
}
public void saveOrUpdate(T t) {
getSession().saveOrUpdate(t);
}
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public Session getCurrentSession() {
return sessionFactory.getCurrentSession();
}
}
Can you help me? Where is the problem?
Invocation of init method failed. You could try to add this:
#Autowired
public void init(SessionFactory factory) {
setSessionFactory(factory);
}
to your GenericDAO.

Resources