Problem description: I have trouble setting up a mock for a particular spring bean to return the correct mock test resource location on my development box, rather than the runtime web application root. I am sure I am doing something silly with my refactoring. I hope someone sees it.
I am using Quartz to execute a job over Spring. The Quartz job is working fine and picking up the Spring applicationcontext ok. The only thing left is to wire up a configuration property for the test or runtime location where the web resources are located. :
JUnit 4, Spring 3.1, Quartz, Java 8, Mockito
The interface:
public interface ITitle {
/**
* Gets the root of the application.
* #return location String
*/
public String getRuntimeLocation();
}
The implementation:
#Component("Title")
public class Title implements ITitle, ApplicationContextAware {
private String location;
/**
* Gets the root of the application.
* #return location String
*/
public String getRuntimeLocation() {
String location = "";
config = getConfig();
log.debug("Class Title --- Method getRuntimeLocation -- config is " + config );
location = config.getRuntimeLocation();
log.debug("Class Title --- Method getRuntimeMethod -- runtime location is " + location );
return location;
}
}
The Unit Test
import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.generators.analytics.serialised.ITitle;
import java.io.File;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.when;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {
"classpath*:/WEB-INF/conf/analytics-context.xml"
})
public class GeneratorTest {
private AnalyticsGenerator generator;
#Mock
private IConfig config;
#Mock
private ApplicationContext applicationContext;
#Mock
private ITitle title;
// Set a logger
private static Logger log = LoggerFactory.getLogger(GeneratorTest.class);
private JobExecutionContext job;
/**
* Initialises the test parameters.
*/
#Before
public void setUp() throws Exception {
//create a generator object
generator = new AnalyticsGenerator();
MockitoAnnotations.initMocks(this);
when(applicationContext.getBean("Query")).thenReturn(query);
when(applicationContext.getBean("Config")).thenReturn(config);
when(config.getRuntimeLocation()).thenReturn(“/Users/me/dev/workarea/");
generator.executeInternal(ctx);
}
/**
* Expected: Json exists
*/
#Test
public void testThatExecuteInternalCreatesAJsonFile() throws JobExecutionException {
generator.executeInternal(job);
File returnedJson = new File("classpath:/google-analytics.json");
Assert.assertNotNull("The JSON file does not exist", returnedJson );
}
/**
* Remove objects from memory.
*/
#After
public void tearDown() throws Exception {
generator = null;
}
}
The spring xml file
<?xml version="1.0" encoding="UTF-8"?>
<!--
* analytics-context.xml
*
* resource configuration file for Google Analytics recommendations integration framework.
*
* All custom beans and services must be defined in this file.
-->
<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:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:ehcache="http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.2.xsd
http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring
http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring/ehcache-spring-1.1.xsd">
<context:annotation-config/>
<!--
START Globally used Google Analytics Query parameters
-->
<bean id="Config" class=“com.generators.analytics.Config">
<property name="reportLocation" value="/data/runtime/web/assets/generated-list/google-analytics.json"/>
<property name="runtimeLocation" value="/data/runtime/web/"/>
</bean>
<bean id="configFactory" class="org.springframework.beans.factory.config.ServiceLocatorFactoryBean">
<property name="serviceLocatorInterface" value=“com.generators.analytics.ConfigFactory" />
</bean>
<alias name="Config" alias="C" />
<bean id="Title" class=“com.generators.analytics.serialised.Title">
<property name="config" ref="Config"/>
</bean>
<context:component-scan base-package=“com.generators.analytics" />
<!--
END Globally used Google Analytics Query parameters
-->
After running the test I get this in the log:
11:51:43.020 [main] DEBUG com.generators.analytics.serialised.Title - Class Title --- Method getConfig -- applicationContext is org.springframework.context.support.GenericApplicationContext#57f23557: startup date [Tue Jan 24 11:51:31 GMT 2017]; root of context hierarchy
11:51:43.020 [main] DEBUG com.generators.analytics.serialised.Title - Class Title --- Method getConfig -- config is com.generators.analytics.Config#13d9cbf5
11:51:43.020 [main] DEBUG com.generators.analytics.serialised.Title - Class Title --- Method getRuntimeLocation -- config is com.generators.analytics.Config#13d9cbf5
11:51:43.020 [main] DEBUG com.generators.analytics.serialised.Title - Class Title --- Method getRuntimeMethod -- runtime location is /data/runtime/web/
The question is, is there anything obvious that I do wrong to get the intended path /Users/me/dev/workarea/ ?
I guess I need to do refactoring to extract the location from the method ? I am not sure how to refactor this particular step.
when(config.getRuntimeLocation()).thenReturn(“/Users/me/dev/workarea/");
I resolved this problem by creating a copy of the spring configuration file and changing
<bean id="Config" class="com.generators.analytics.Config">
<property name="reportLocation" value="/Users/arnout/dev/soton-test/workarea/assets/generated-list/google-analytics.json"/>
<property name="runtimeLocation" value="/Users/arnout/dev/soton-test/workarea/"/>
</bean>
and then changing
#ContextConfiguration(locations = {
"classpath*:/WEB-INF/conf/livesite_customer/resources/test-analytics-resource-config.xml"
})
public class GeneratorTest {
I did some lateral thinking after I read up on Profiles in Spring configurations. In fact I did not need a profile, it was just as easy as taking another spring configuration in test mode.
Related
I am building a web application using spring MVC which is connected to the database. This is part of my bean config file.
<!-- Define Database DataSource / connection pool -->
<bean id="myDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/java_task?useSSL=false" />
<property name="user" value="me" />
<property name="password" value="me" />
<!-- these are connection pool properties for C3P0 -->
<property name="minPoolSize" value="5" />
<property name="maxPoolSize" value="20" />
<property name="maxIdleTime" value="30000" />
</bean>
<!-- Define Hibernate session factory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="myDataSource" />
<property name="packagesToScan" value="com.javatask.entity" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
As you can see my data source is defined in a hard way. In code I am using #Autowired annotation to inject sessionFactory. But I would like to inject sessionFactory (jdbc, username, password etc.) with data which I will obtain from user during run time. For example he will write me those data to the textfeild and then I will create sessionFactory (based on his data) which will be connected to his database.
I was looking for an answer but unluckily I have not found anything that would fit to this problem.
There are multiple ways that spring bean definition can be changed in run time. One way is to refresh the Spring Application Context in run time which would have the bean definition specific to the functionality rather than all bean definition.
((ConfigurableApplicationContext)applicationContext).refresh();
Let me explain using one simple use case:
Create a PropertyBean which will load value from external properties file.
Create PropertiesApplicationContext which would have only PropertyBean definition config rather than all beans belongs the application.
Use ConfigurableApplicationContext refresh() method to reload ProperiesBean definition in run time.
More details about below example code snippet:
Web Application should display a Property Value from a bean which
will read the value from a external property file.
Property value will change anytime in external properties file.
Web Application should not restarted.
Here, bean definition should be changed in run time.
Spring Boot Application Code:
#SpringBootApplication(scanBasePackages = {"vijay.controller","vijay.configuration"})
public class SpringContextRefreshApplication extends SpringBootServletInitializer{
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(SpringContextRefreshApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(SpringContextRefreshApplication.class, args);
}
}
MVC Configuration:
package vijay.configuration;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
/**
* MVC Configuration
* #author Vijay
*/
#Configuration
public class MvcConfiguration extends WebMvcConfigurerAdapter{
#Override
public void configureViewResolvers(ViewResolverRegistry registry) {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/view/");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
registry.viewResolver(resolver);
}
}
Custom (Property) Application Context Aware:
package vijay.configuration;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* PropertyApplicationContext Class to load Property Configuration XML.
* #author Vijay
*/
public class PropertyApplicationContext implements ApplicationContextAware{
private ApplicationContext applicationContext;
private static PropertyApplicationContext propertyApplicationContext;
private PropertyApplicationContext(){
applicationContext = new ClassPathXmlApplicationContext("property-config.xml");
}
#Override
public void setApplicationContext(ApplicationContext ac) throws BeansException {
if(applicationContext == null){
this.applicationContext = ac;
}
}
public ApplicationContext getApplicationContext(){
return applicationContext;
}
public static PropertyApplicationContext getInstance(){
if(propertyApplicationContext == null){
propertyApplicationContext = new PropertyApplicationContext();
}
return propertyApplicationContext;
}
}
MVC Controller:
package vijay.controller;
import vijay.beans.PropertyDto;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import vijay.configuration.PropertyApplicationContext;
/**
* Property List Controller.
* #author Vijay
*/
#Controller
public class PropertyController {
#RequestMapping("/")
public String testController(){
System.out.println("vijay.controller.PropertyController.testController()");
return "sample";
}
#RequestMapping(path = "/getProperties")
public String testPropertiesController(ModelMap modelMap){
ApplicationContext applicationContext = PropertyApplicationContext.getInstance().getApplicationContext();
PropertyDto propertyDto = (PropertyDto) applicationContext.getBean("propertyBean");
System.out.println("vijay.controller.PropertyController.testPropertiesController() " + propertyDto);
modelMap.addAttribute("message", propertyDto.getKey());
return "sample";
}
/**
* Method will refresh ApplicationContext
* #param modelMap as ModelMap
* #return viewName as String
*/
#RequestMapping(path = "/refreshProperties")
public String refreshBean(ModelMap modelMap){
ApplicationContext applicationContext = PropertyApplicationContext.getInstance().getApplicationContext();
// Refresh Application Context
((ConfigurableApplicationContext)applicationContext).refresh();
PropertyDto propertyDto = (PropertyDto) applicationContext.getBean("propertyBean");
System.out.println("vijay.controller.PropertyController.refreshBean()" + propertyDto);
modelMap.addAttribute("message", propertyDto.getKey());
return "sample";
}
}
Spring Bean (Property-config.xml) definition 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"
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.xsd" >
<bean id="placeholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="file:C://sample.properties" />
</bean>
<context:annotation-config/>
<context:component-scan base-package="vijay.beans"/>
</beans>
View JSP (sample.jsp):
<!DOCTYPE html>
<%# taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<html lang="en">
<body>
<div>
<div>
<h1>Spring Boot JSP Example</h1>
<h2>Property Value :: ${message} !</h2>
</div>
</div>
</body>
</html>
Here, MVC Controller has /refreshProperties which will refresh the PropertiesBean defined in PropertiesApplicationContext. As properties-config.xml the only bean definition defined in PropertiesApplicationContext, propertiesBean alone will be refreshed and no other bean definition will be refreshed.
Similar way, you can create Application Context by extending ApplicationContextAware which will have bean definition of sessionFactory. You can get SessionFactory wherever required from this context and refresh the context wherever required.
This is one way to achieve the bean definition change in run time.
Did you try this [Change SessionFactory datasource jdbcurl late in runtime] (Change SessionFactory datasource jdbcurl late in runtime)?
i'm new to Spring and Spring integration, and i have a simple task to accomplish. Filtering some emails by it's subject though a regex and register some info in the db.
I've set the JavaMailProperties and the test gives me the output of the read emails but the method i'm setting with service-activator is never called and this is actually making me have a strong headache.
The following is the xml configuration 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:mail="http://www.springframework.org/schema/integration/mail"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/integration/mail
http://www.springframework.org/schema/integration/mail/spring-integration-mail-3.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">
<util:properties id="javaMailProperties">
<prop key="mail.store.protocol">pop3</prop>
<prop key="mail.debug">true</prop>
</util:properties>
<mail:inbound-channel-adapter id="pop3Adapter"
store-uri="pop3://username:password#mail..example.com:110/INBOX"
channel="recieveEmailChannel"
should-delete-messages="false"
auto-startup="true"
java-mail-properties="javaMailProperties"
mail-filter-expression="subject matches '(^Presente+\\s([1-9]{1})+(\\s[-]\\s)+([A-Z]{4,})+(\\s[A-Z]{6,})$)'">
<int:poller max-messages-per-poll="10" fixed-delay="10000"/>
</mail:inbound-channel-adapter>
<int:channel id="recieveEmailChannel">
<int:interceptors>
<int:wire-tap channel="logger"/>
</int:interceptors>
</int:channel>
<int:logging-channel-adapter id="logger" level="DEBUG"/>
<int:service-activator input-channel="recieveEmailChannel" ref="leggiMail" method="processa_mail"/>
<bean id="leggiMail" class="it.jenia.ac.mail.rapportini.LeggiMail">
</bean>
</beans>
The LeggiMail class with the processa_mail method is very simple:
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.stereotype.Service;
#Service
public class LeggiMail {
private static Logger logger = Logger.getLogger(LeggiMail.class);
public static int count_get = 0;
#ServiceActivator
public void processa_mail(MimeMessage mimeMessage) {
count_get++;
logger.debug("porcessa_mail working");
}
The test class i'm using this application in:
#ContextConfiguration(locations = { "classpath*:/test-spring-configuration.xml" })
#RunWith(SpringJUnit4ClassRunner.class)
#TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, TransactionalTestExecutionListener.class })
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
public class LeggiMailTest {
private static Logger logger = Logger.getLogger(LeggiMailTest.class);
#Autowired
LeggiMail lm;
#Test
#Transactional(value = "transactionManager", propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Exception.class)
public void test_processa_mail(){
logger.debug("Test started");
}
}
The log Test started appears correctly in the console, but the log porcessa_mail working never shows up..
The first tutorial i found on this subject just spoke about a method that would have been called by default by the context. http://blog.solidcraft.eu/2011/04/read-emails-from-imap-with-spring.html (And it says that the method "processa_mail" should be called by default when the context is loaded, cause it's a service-activator.
Reading this tutorial about service activator didn't help enough: http://docs.spring.io/spring-integration/reference/html/messaging-endpoints-chapter.html
When you try to test some async stuff you some barrier to prevent the main thread to be stopped early, than it is neccessary for entire test-case.
The simples way is add Thread.sleep() before the end of test method.
But better solution is based on some synchonizer, like CountDonwLatch.
From other side there is QueueChannel in the Spring Integration. You can use it as an output-channel for <service-activator>. Inject it to the test class and wait on the output.receive(10000). And assert... the result message to make your test realy unit-test.
I have this web.xml file
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-context.xml /WEB-INF/core-spring-beans.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
and applicationContext that include the Bean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
<tx:annotation-driven transaction-manager="txManager"/>
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource"/>
<jee:jndi-lookup id="dataSource" jndi-name="pull_DS" resource-ref="true"/>
<bean id="sqlMapClient"
class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"
p:configLocation="classpath:pull/DBUtils/sqlMapConfig.xml"
p:dataSource-ref="dataSource"/>
<bean id="daoBase" abstract="true"
p:sqlMapClient-ref="sqlMapClient"/>
<bean id="Photo"
class="pull.DBUtils.PopPhotoImpl"
parent="daoBase"/>
<bean id="Trunkcate"
class="pull.DBUtils.TrunkcateCifSrcImpl"
parent="daoBase"/>
<bean id="applicationContextProvder"class="pull.DBUtils.ApplicationContextProvider"/>
</beans>
and the ApplicationContextProvider.java for ApplicationContext
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext ctx = null;
public static ApplicationContext getApplicationContext() {
return ctx;
}
public void setApplicationContext(ApplicationContext ctx)
throws BeansException {
this.ctx = ctx;
}
}
AND so I defined a method returnCleanUp in TrunkcateCifSrcImpl Bean as
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
public class TrunkcateCifSrcImpl extends iBatisTemplate implements TrunkcateCifSrc{
public int retTrunkcateReady() {
return super.trunkcateReady("CifSrc_Trunkcate.cleanUp");
}
public static int returnCleanUp() {
TrunkcateCifSrcImpl trunkcate = null;
int result;
try {
ApplicationContext ctx = ApplicationContextProvider
.getApplicationContext();
trunkcate = (TrunkcateCifSrcImpl) ctx.getBean("Trunkcate");
result = trunkcate.retTrunkcateReady();
}
catch (NoSuchBeanDefinitionException noBeanE) {
throw noBeanE;
} catch (BeansException beanE) {
throw beanE;
}
catch (Exception e) {
throw e;
}
return result;
}
}
The iBatisTemplate class to return a value of map "trunkcateReady" (value returns back from iBatis function called from database)
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.ibatis.SqlMapClientCallback;
import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;
import com.ibatis.sqlmap.client.SqlMapExecutor;
public class iBatisTemplate extends SqlMapClientDaoSupport {
public int trunkcateReady(final String id) {
Map<String, Integer> map = new HashMap<String, Integer>(1);
getSqlMapClientTemplate().queryForObject(id, map);
return map.get("trunkcateReady");
}
}
but now once in awhile if i call this method from Trunkcate bean I would receive that exceptionm IllegalStateException, does anyone know what can I do to fix this??
do{
cleanUp = TrunkcateCifSrcImpl.returnCleanUp();
if(cleanUp==1)
{
logger.debug("Going to sleep........");
Thread.sleep(65000);
}
}while(cleanUp!=0);
Stack trace exception I got, this usually happens the first time it go through the loop then after Thread.sleep(65000), it will go back in normally
2014-02-14 12:23:45,646 GMT-0800 [managedServer=weeManagedServer-1]pull.quartzScheduler.PullingPDRTask - Pull failed....
java.lang.IllegalStateException: BeanFactory not initialized or already closed - call 'refresh' before accessing beans via the ApplicationContext
at org.springframework.context.support.AbstractRefreshableApplicationContext.getBeanFactory(AbstractRefreshableApplicationContext.java:172)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1093)
at pull.DBUtils.TrunkcateCifSrcImpl.returnCleanUp(TrunkcateCifSrcImpl.java:21)
at pull.quartzScheduler.PullingPDRTask.excute(PullingPDRTask.java:257)
at pull.quartzScheduler.SchedulerService.executePullingPDRTask(SchedulerService.java:31)
at pull.quartzScheduler.PullStatefulJob.executeInternal(PullStatefulJob.java:42)
at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:113)
at org.quartz.core.JobRunShell.run(JobRunShell.java:216)
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:549)
Thanks! any input would be helpful. I deploy my app on weblogic server 1036jdk1.7. Using spring 3.1.1. Thanks all!
I had a similar Issue when i worked on Spring MVC using Tomcat 6 but i had by mistake declared multiple bean classes with the same name , check your classes once for ambiguity . Please post the complete stack trace .
Just In case if it helps this was my mistake so i got that error .
Annotation-specified bean name 'countryServiceImpl' for bean class [com.ssrv.fms.service.contact.impl.CountryServiceImpl] conflicts with existing, non-compatible bean definition of same name and class [com.ssrv.fms.service.admin.impl.CountryServiceImpl]
You can check the target folder of your project, and check if the configuration files are there.
And I think you should tell more details of the errorInfo, it will be helpful.
I've met the same problem you have. But I had more detail error information under the
BeanFactory not initialized or already closed - call 'refresh' before accessing beans via the ApplicationContext
It says
Caused by: java.io.FileNotFoundException: class path resource [spring/] cannot be resolved to URL because it does not exist
So I check the target folder of the project, the "spring" folder is missing, which all of my configuration files in it. Although I don't know why it's not in there.
So I delete the target folder of the project, and rebuild it. And problem's solved. The 'spring' folder appeared.
Before and after:
UPDATE 25-11-2012
Hi it seems that my context files was in the wrong 'classpath' They had to be in the test classpath. I solved this by adding a folder called resources to the src/test/ folder. In here I could put my application contexts. I have also removed the #TestExecutionListeners from the test. I also needed to add some dependencies to my pom file for javax/servlet/serlvetException and such. If anyone is interested my code can be seen at Github, under the branch issue9.
Question [Solved]
I have made a simple application, by using spring 3. I have made a service class which uses a DAO class to map things to and from the database, by using the simple JDBC template.
My problem is when i am trying to make an integration test on these classes, it return a NullPointerException (See Stacktrace). It is really annoying since I can't seem to find the answer, so I hope you guys can help me out. Below I have posted all my different files.
Stacktrace
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.115 sec <<< FAILURE!
test(dk.martinrohwedder.blog.test.ArticleServiceTest) Time elapsed: 0.009 sec <<< ERROR!
java.lang.NullPointerException
at dk.martinrohwedder.blog.service.ArticleService.getFiveLastArticles(ArticleService.java:30)
at dk.martinrohwedder.blog.test.ArticleServiceTest.test(ArticleServiceTest.java:57)
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:601)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:30)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:53)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:123)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:104)
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:601)
at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:164)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:110)
at org.apache.maven.surefire.booter.SurefireStarter.invokeProvider(SurefireStarter.java:175)
at org.apache.maven.surefire.booter.SurefireStarter.runSuitesInProcessWhenForked(SurefireStarter.java:107)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:68)
ArticleServiceTest
package dk.martinrohwedder.blog.test;
import dk.martinrohwedder.blog.domain.Article;
import dk.martinrohwedder.blog.service.ArticleService;
import java.util.ArrayList;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.transaction.annotation.Transactional;
/**
*
* #author Martin Rohwedder
*/
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"classpath:test-context.xml"})
#TestExecutionListeners
#TransactionConfiguration(defaultRollback = true)
#Transactional
public class ArticleServiceTest {
#Autowired(required = true)
private ArticleService articleService;
//private EmbeddedDatabase db;
#Before
public void setUp() {
//EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
//db = builder.setType(EmbeddedDatabaseType.HSQL).setName("blog").addScript("classpath:create-db.sql").addScript("classpath:test-data.sql").build();
//articleService.getArticleDao().setDataSource(db);
//articleService = new ArticleService();
}
#After
public void tearDown() {
//articleService.getArticleDao().setDataSource(null);
//db.shutdown();
//articleService = null;
}
#Test
public void test()
{
ArrayList<Article> articles = articleService.getFiveLastArticles();
int number = articles.size();
assertEquals(3, number);
}
}
ArticleService
package dk.martinrohwedder.blog.service;
import dk.martinrohwedder.blog.domain.Article;
import dk.martinrohwedder.blog.repository.ArticleDao;
import java.util.ArrayList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
*
* #author Martin Rohwedder
* #since 22-11-2012
* #version 1.0
*/
#Service("articleService")
public class ArticleService {
#Autowired(required = true)
private ArticleDao articleDao;
public ArticleDao getArticleDao() {
return articleDao;
}
public void setArticleDao(ArticleDao articleDao) {
this.articleDao = articleDao;
}
public ArrayList<Article> getFiveLastArticles()
{
ArrayList<Article> articles = (ArrayList) articleDao.selectAllArticles();
if (articles.size() > 5) {
articles = (ArrayList) articles.subList(articles.size() - 6, articles.size());
}
return articles;
}
}
ArticleDao
package dk.martinrohwedder.blog.repository;
import dk.martinrohwedder.blog.domain.Article;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
/**
*
* #author Martin Rohwedder
* #since 22-11-2012
* #version 1.0
*/
#Repository
public class ArticleDao implements IArticleDao {
private JdbcTemplate jdbcTemplate;
#Autowired(required = true)
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
#Override
public List<Article> selectAllArticles() {
String sql = "select article_id, headline from article";
return this.jdbcTemplate.query(sql, new ArticleMapper());
}
#Override
public Article selectArticle(int articleId) {
throw new UnsupportedOperationException("Not supported yet.");
}
#Override
public void insertArticle(Article article) {
throw new UnsupportedOperationException("Not supported yet.");
}
#Override
public void updateArticle(Article article) {
throw new UnsupportedOperationException("Not supported yet.");
}
#Override
public void deleteArticle(int articleId) {
throw new UnsupportedOperationException("Not supported yet.");
}
/**
* Article Mapper is responsible for map all rows found in a sql
* statement to Article objects.
*/
private static final class ArticleMapper implements RowMapper<Article> {
#Override
public Article mapRow(ResultSet rs, int rowNum) throws SQLException {
Article article = new Article();
article.setId(rs.getInt("article_id"));
article.setHeadline(rs.getString("headline"));
return article;
}
}
}
test-context.xml
<?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:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd 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/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd">
<context:component-scan base-package="dk.martinrohwedder.blog" />
<mvc:annotation-driven />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/views/" />
<property name="suffix" value=".jsp" />
</bean>
<bean id="embeddedDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbc.JDBCDriver"/>
<property name="url" value="jdbc:hsqldb:mem:blog"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
</bean>
<jdbc:embedded-database id="dataSource" type="HSQL"/>
<jdbc:initialize-database data-source="embeddedDataSource">
<jdbc:script location="classpath:create-db.sql"/>
<jdbc:script location="classpath:test-data.sql"/>
</jdbc:initialize-database>
</beans>
create-db.sql
create database if not exists blog;
use blog;
drop table if exists article;
create table article
(
article_id int unsigned not null auto_increment,
headline varchar(30) not null,
primary key (article_id)
);
test-data.xml
insert into article (article_headline)
values ("Artikel 1");
insert into article (article_headline)
values ("Artikel 2");
insert into article (article_headline)
values ("Artikel 3");
Both test-context.xml, create-db.sql and test-data.sql is in the classpath since they are in the package called Other Sources (src/main/resources).
Hopes that anyone can help me out.
Try using
<context:annotation-config/>
instead of
<mvc:annotation-driven />
in your test-context.xml file.
<mvc:annotation-driven/> is a tag added in Spring 3.0 which does the following:
Configures the Spring 3 Type ConversionService (alternative to
PropertyEditors)
Adds support for formatting Number fields with #NumberFormat
Adds support for formatting Date, Calendar, and Joda Time fields with #DateTimeFormat, if Joda Time is on the classpath
Adds support for validating #Controller inputs with #Valid, if a JSR-303 Provider is on the classpath
Adds support for support for reading and writing XML, if JAXB is on the classpath (HTTP message conversion with #RequestBody/#ResponseBody)
Adds support for reading and writing JSON, if Jackson is o n the classpath (along the same lines as #5)
<context:annotation-config/>
Looks for annotations on beans in the same application context it is defined and declares support for all the general annotations like #Autowired, #Resource, #Required, #PostConstruct etc etc.
It looks to me like articleDao is not being set. If you want to use a Spring bean in the test then you can't instantiate the service in your test. Take this line out...
articleService = new ArticleService();
Spring has a very handy convenience class called PropertyPlaceholderConfigurer, which takes a standard .properties file and injects values from it into your bean.xml config.
Does anyone know of a class which does exactly the same thing, and integrates with Spring in the same way, but accepts XML files for the config. Specifically, I'm thinking of Apache digester-style config files. It would be easy enough to do this, I'm just wondering if anyone already has.
Suggestions?
I just tested this, and it should just work.
PropertiesPlaceholderConfigurer contains a setPropertiesPersister method, so you can use your own subclass of PropertiesPersister. The default PropertiesPersister already supports properties in XML format.
Just to show you the fully working code:
JUnit 4.4 test case:
package org.nkl;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
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;
#ContextConfiguration(locations = { "classpath:/org/nkl/test-config.xml" })
#RunWith(SpringJUnit4ClassRunner.class)
public class PropertyTest {
#Autowired
private Bean bean;
#Test
public void testPropertyPlaceholderConfigurer() {
assertNotNull(bean);
assertEquals("fred", bean.getName());
}
}
The spring config file test-config.xml
<?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"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
">
<context:property-placeholder
location="classpath:/org/nkl/properties.xml" />
<bean id="bean" class="org.nkl.Bean">
<property name="name" value="${org.nkl.name}" />
</bean>
</beans>
The XML properties file properties.xml - see here for description of usage.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<entry key="org.nkl.name">fred</entry>
</properties>
And finally the bean:
package org.nkl;
public class Bean {
private String name;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
Hope this helps...
Found out that Spring Modules provide integration between Spring and Commons Configuration, which has a hierarchial XML configuration style. This ties straight into PropertyPlaceholderConfigurer, which is exactly what I wanted.
Been trying to come up with a nice solution to this myself that
Revolves around creating an XSD for the config file - since in my mind the whole benefit of using XML is that you can strongly type the config file, in terms of datatypes, and which fields are mandatory/optional
Will validate the XML against the XSD, so if a value is missing it'll throw an error out rather than your bean being injected with a 'null'
Doesn't rely on spring annotations (like #Value - in my mind that's giving beans knowledge about their container + relationship with other beans, so breaks IOC)
Will validate the spring XML against the XSD, so if you try to reference an XML field not present in the XSD, it'll throw out an error too
The bean has no knowledge that its property values are being injected from XML (i.e. I want to inject individual properties, and not the XML object as a whole)
What I came up with is as below, apologies this is quite long winded, but I like it as a solution since I believe it covers everything. Hopefully this might prove useful to someone. Trivial pieces first:
The bean I want property values injected into:
package com.ndg.xmlpropertyinjectionexample;
public final class MyBean
{
private String firstMessage;
private String secondMessage;
public final String getFirstMessage ()
{
return firstMessage;
}
public final void setFirstMessage (String firstMessage)
{
this.firstMessage = firstMessage;
}
public final String getSecondMessage ()
{
return secondMessage;
}
public final void setSecondMessage (String secondMessage)
{
this.secondMessage = secondMessage;
}
}
Test class to create the above bean and dump out the property values it got:
package com.ndg.xmlpropertyinjectionexample;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public final class Main
{
public final static void main (String [] args)
{
try
{
final ApplicationContext ctx = new ClassPathXmlApplicationContext ("spring-beans.xml");
final MyBean bean = (MyBean) ctx.getBean ("myBean");
System.out.println (bean.getFirstMessage ());
System.out.println (bean.getSecondMessage ());
}
catch (final Exception e)
{
e.printStackTrace ();
}
}
}
MyConfig.xsd:
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:myconfig="http://ndg.com/xmlpropertyinjectionexample/config" targetNamespace="http://ndg.com/xmlpropertyinjectionexample/config">
<xsd:element name="myConfig">
<xsd:complexType>
<xsd:sequence>
<xsd:element minOccurs="1" maxOccurs="1" name="someConfigValue" type="xsd:normalizedString" />
<xsd:element minOccurs="1" maxOccurs="1" name="someOtherConfigValue" type="xsd:normalizedString" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
Sample MyConfig.xml file based on the XSD:
<?xml version="1.0" encoding="UTF-8"?>
<config:myConfig xmlns:config="http://ndg.com/xmlpropertyinjectionexample/config">
<someConfigValue>First value from XML file</someConfigValue>
<someOtherConfigValue>Second value from XML file</someOtherConfigValue>
</config:myConfig>
Snippet of pom.xml file to run xsd2java (wasn't much else in here besides setting to Java 1.6, and spring-context dependency):
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<executions>
<execution>
<id>main-xjc-generate</id>
<phase>generate-sources</phase>
<goals><goal>generate</goal></goals>
</execution>
</executions>
</plugin>
Now the spring XML itself. This creates a schema/validator, then uses JAXB to create an unmarshaller to create a POJO from the XML file, then uses spring # annotation to inject property values by quering the POJO:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd" >
<!-- Set up schema to validate the XML -->
<bean id="schemaFactory" class="javax.xml.validation.SchemaFactory" factory-method="newInstance">
<constructor-arg value="http://www.w3.org/2001/XMLSchema"/>
</bean>
<bean id="configSchema" class="javax.xml.validation.Schema" factory-bean="schemaFactory" factory-method="newSchema">
<constructor-arg value="MyConfig.xsd"/>
</bean>
<!-- Load config XML -->
<bean id="configJaxbContext" class="javax.xml.bind.JAXBContext" factory-method="newInstance">
<constructor-arg>
<list>
<value>com.ndg.xmlpropertyinjectionexample.config.MyConfig</value>
</list>
</constructor-arg>
</bean>
<bean id="configUnmarshaller" class="javax.xml.bind.Unmarshaller" factory-bean="configJaxbContext" factory-method="createUnmarshaller">
<property name="schema" ref="configSchema" />
</bean>
<bean id="myConfig" class="com.ndg.xmlpropertyinjectionexample.config.MyConfig" factory-bean="configUnmarshaller" factory-method="unmarshal">
<constructor-arg value="MyConfig.xml" />
</bean>
<!-- Example bean that we want config properties injected into -->
<bean id="myBean" class="com.ndg.xmlpropertyinjectionexample.MyBean">
<property name="firstMessage" value="#{myConfig.someConfigValue}" />
<property name="secondMessage" value="#{myConfig.someOtherConfigValue}" />
</bean>
</beans>
I'm not sure about the Apache digester-style config files, but I found a solution that was not that hard to implement and suitable for my xml config-file.
You can use the normal PropertyPlaceholderConfigurer from spring, but to read your custom config you have to create your own PropertiesPersister, where you can parse the xml (with XPath) and set the required properties yourself.
Here's a small example:
First create your own PropertiesPersister by extending the default one:
public class CustomXMLPropertiesPersister extends DefaultPropertiesPersister {
private XPath dbPath;
private XPath dbName;
private XPath dbUsername;
private XPath dbPassword;
public CustomXMLPropertiesPersister() throws JDOMException {
super();
dbPath = XPath.newInstance("//Configuration/Database/Path");
dbName = XPath.newInstance("//Configuration/Database/Filename");
dbUsername = XPath.newInstance("//Configuration/Database/User");
dbPassword = XPath.newInstance("//Configuration/Database/Password");
}
public void loadFromXml(Properties props, InputStream is)
{
Element rootElem = inputStreamToElement(is);
String path = "";
String name = "";
String user = "";
String password = "";
try
{
path = ((Element) dbPath.selectSingleNode(rootElem)).getValue();
name = ((Element) dbName.selectSingleNode(rootElem)).getValue();
user = ((Element) dbUsername.selectSingleNode(rootElem)).getValue();
password = ((Element) dbPassword.selectSingleNode(rootElem)).getValue();
}
catch (JDOMException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
props.setProperty("db.path", path);
props.setProperty("db.name", name);
props.setProperty("db.user", user);
props.setProperty("db.password", password);
}
public Element inputStreamToElement(InputStream is)
{
...
}
public void storeToXml(Properties props, OutputStream os, String header)
{
...
}
}
Then inject the CustomPropertiesPersister to the PropertyPlaceholderConfigurer in the application context:
<beans ...>
<bean id="customXMLPropertiesPersister" class="some.package.CustomXMLPropertiesPersister" />
<bean id="propertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_FALLBACK" />
<property name="location" value="file:/location/of/the/config/file" />
<property name="propertiesPersister" ref="customXMLPropertiesPersister" />
</bean>
</beans>
After that you can use your properties like this:
<bean id="someid" class="some.example.class">
<property name="someValue" value="$(db.name)" />
</bean>