Run a testsuite in multiple environment - spring

I want to run my test suite in multiple environment like below:
ApplicationContextTest.class
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("/application-context.xml")
public class MyTest{
#Autowired
private ApplicationContext applicationContext;
#Test
public void test1() {
((ConfigurableEnvironment)applicationContext.getEnvironment()).setActiveProfiles("env1");
((GenericXmlApplicationContext)applicationContext).refresh();
}
#Test
public void test2() {
((ConfigurableEnvironment)applicationContext.getEnvironment()).setActiveProfiles("env2");
((GenericXmlApplicationContext)applicationContext).refresh();
}
}
applicationContext.xml
<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:mvc="http://www.springframework.org/schema/mvc"
xmlns:aop="http://www.springframework.org/schema/aop"
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.1.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">
<beans profile="env1">
</beans>
<beans profile="env2">
</beans>
When I run test, I got an exception
Caused by: java.lang.IllegalStateException: GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once
Are there any ways to set Active Profile after ApplicationContext started up?
Or Any solution to solve above exception?
Thanks.

The normal way to choose one or more specific profile(s) is to set a system property when running the tests
-Dspring.profiles.active=env1
You can also set one or more profile(s) as default with the system property
-Dspring.profiles.default=env1
I normally do this in a static init method of my test
#BeforeClass
public static void init() {
// set default spring test profile
System.setProperty("spring.profiles.default", "default");
}
You will find some information if you search for these properties (If you need a Spring code reference you have to look at the AbstractEnvironment class).
I do not know of any way how to change the profile after startup. In this case you may have to use a new JVM on each test (can e.g. be done by the maven surefire plugin using the reuseForks setting). Or even better place the tests that use the same profile in the same test class and set the profile as needed.
IMHO a test should not depend on a specific profile. A test should pass - whatever profile is used. Than you can easily change e.g. between test (mock) or 'real' environments.

Related

The requested resource is not available error in Spring Web MVC

Dear Altruist,
I am trying to run Spring Web MVC HelloWeb project but it always shows "The requested resource is not available" error.
Would you please help me regarding this problem?
Project Structure:
web.xml file:
HelloWeb-servlet.xml file:
HelloController.java file:
Based on the error message it seems you do not have your context defined in Tomcat.
Include a file named context.xml, into the META-INF folder, with the content:
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/HelloWeb"/>
From the tomcat documentation:
Tomcat Context Container Documentation
Individual Context elements may be explicitly defined:
In an individual file at /META-INF/context.xml inside the application
files. Optionally (based on the Host's copyXML attribute) this may be
copied to $CATALINA_BASE/conf/[enginename]/[hostname]/ and renamed to
application's base file name plus a ".xml" extension.
Also, return a ModelView object instead of a String to get redirected to your home.jsp page.
#RequestMapping(method = RequestMethod.GET)
protected ModelAndView printHello(HttpServletRequest request,
HttpServletResponse response) throws Exception {
ModelAndView model = new ModelAndView("hello");
return model;
}
Replace your beans tag like this.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"
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.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">

No Spring Bean found in EJB with SpringBeanAutowiringInterceptor

I need some help: I have one EAR-File, containing one WAR-File, one EJB-Jar-File and some "shared" libs:
aopalliance-1.0.jar commons-logging-1.1.1.jar log4j-1.2.16.jar spring-aop-4.0.5.RELEASE.jar spring-beans-4.0.5.RELEASE.jar spring-context-4.0.5.RELEASE.jar spring-context-support-4.0.5.RELEASE.jar spring-core-4.0.5.RELEASE.jar spring-expression-4.0.5.RELEASE.jar
The War File has a Context initializer which find the spring config and loads everything well.
I now want to use another Spring Context for the EJB Jar.
My EJB is defined as
#Stateless(mappedName = "ejb/SpringRocks")
#RemoteHome(com.ibm.websphere.ola.ExecuteHome.class)
#Interceptors(SpringBeanAutowiringInterceptor.class)
public class WolaUseCaseOne {
#Autowired
private DummyService dummyService;
/* ...More stuff here */
Inside the EJB-JAR, there is also a beanRefContext.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myEjb" name="myEjb" class="org.springframework.context.support.ClassPathXmlApplicationContext">
<constructor-arg value="classpath*:META-INF/spring/simpleEjb.xml" />
</bean>
</beans>
The simpleEjb.xml is is also inside the EJB-Jar and is defining a very simple Bean:
<?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.xsd">
<bean id="myDummyService" class="com.provinzial.beispielanwendung.batch.wola.DummyServiceImpl" />
</beans>
As described, the WEB Part works perfect, but when the EJB is called, the SpringBeanAutowiringInterceptor is called, but seems to do nothing. What do I have to do, to get a Spring Context created?! My hope was that it is initialized when the EJB is created. I created a Subclass of SpringBeanAutowiringInterceptor with some loggers, but the class is only created, no method is called !
What else do I have to do? Or does anybody have a valid EAR File example?
I think the Problem is that inside the EJB Module no context is initialized...
Greets
Timo
I was facing similar issue with my EJB (no WAR). This is what fixed mine,
I was missing the spring-aop jar on my classpath. I see you have it so good there.
In my ejb-jar.xml file, I set the meta-data flag to true so I did not get prompted on deployment to complete.
I set to "false" for one deployment to see what IBM generated for me. In the ejb-jar.xml it added the following (my MDB is named TaskMDB),
<assembly-descriptor>
<interceptor-binding>
<ejb-name>TaskMDB</ejb-name>
<interceptor-class>org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor</interceptor-class>
</interceptor-binding>
</assembly-descriptor>
<interceptors>
<interceptor>
<interceptor-class>org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor</interceptor-class>
<post-activate>
<lifecycle-callback-class>org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor</lifecycle-callback-class>
<lifecycle-callback-method>autowireBean</lifecycle-callback-method>
</post-activate>
<pre-passivate>
<lifecycle-callback-class>org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor</lifecycle-callback-class>
<lifecycle-callback-method>releaseBean</lifecycle-callback-method>
</pre-passivate>
<post-construct>
<lifecycle-callback-class>org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor</lifecycle-callback-class>
<lifecycle-callback-method>autowireBean</lifecycle-callback-method>
</post-construct>
<pre-destroy>
<lifecycle-callback-class>org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor</lifecycle-callback-class>
<lifecycle-callback-method>releaseBean</lifecycle-callback-method>
</pre-destroy>
</interceptor>
</interceptors>
Then I added what IBM generated (the assembly-descriptor and interceptors stanzas) back to my ejb-jar.xml and set the metadata-complete back to true.
Then it worked. Hope this helps.
Here is the full ejb-jar.xml
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar version="3.1" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd">
<display-name>ares-api-uow-ejb</display-name>
<enterprise-beans>
<message-driven id="TaskMDB">
<ejb-name>TaskMDB</ejb-name>
<ejb-class>something.api.uow.ejb.mdb.TaskMDB</ejb-class>
<messaging-type>javax.jms.MessageListener</messaging-type>
<transaction-type>Bean</transaction-type>
</message-driven>
</enterprise-beans>
</ejb-jar>

NoSuchMethodError in Jetty with Spring Data Mongo custom repository

I have a small web application in development using Maven, Spring MVC and Spring Data Mongo. I am getting a java.lang.NoSuchMethodError when one of my Controllers attempts to access a method defined in a custom repository. The same method works fine when exercised via a JUnit 4 test extending AbstractJUnit4SpringContextTests and using a near-identical XML configuration file.
Standard repository:
public interface IndividualRepository extends MongoRepository<Individual, String>, IndividualRepositoryCustom {
...
}
Custom interface:
public interface IndividualRepositoryCustom {
Individual findByIdentifier(String identifierType, String identifierValue);
}
Custom implementation:
public class IndividualRepositoryImpl implements IndividualRepositoryCustom {
#Autowired
private MongoTemplate mongoTemplate;
#Override
public Individual findByIdentifier(String identifierType, String identifierValue) {
String locator = String.format("identifiers.%s", identifierType);
return mongoTemplate.findOne(query(where(locator).is(identifierValue)), Individual.class);
}
}
dataaccess-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:mongo="http://www.springframework.org/schema/data/mongo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/mongo
http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">
<mongo:repositories base-package="com.myco.dataaccess"/>
<mongo:mongo host="mongo.myco.com" port="27017"/>
<mongo:db-factory dbname="test" mongo-ref="mongo"/>
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg ref="mongo"/>
<constructor-arg value="test"/>
</bean>
</beans>
In my JUnit test I have (excerpt):
#Autowired
private IndividualRepository individualRepo;
...
List<Individual> foundList = individualRepo.findAll();
assertNotNull(foundList);
assertTrue(foundList.size() > 0);
Individual found = individualRepo.findByIdentifier("someid", "123456");
assertNotNull(found);
assertEquals("Bob", found.getFirstName());
The test passes fine, calling both findAll() (standard Repository method) and findByIdentifier() (custom method). The latter fails with NoSuchMethodError when called by a Controller running in a web application in Jetty, while the same Controller can call findAll() with no issues.
This turned out to be nothing to do with Spring Data, but an issue with the way I was using the maven-jetty-plugin with my multi-module build.
Basically, I was running mvn jetty:run for my web module which had a dependency on my dataaccess module (where my JUnit tests lived). As I was rebuilding the project with mvn clean package, the latest versions were not being placed in my local repo, and therefore were not being picked up by the mvn jetty:run process running alongside my build process. Problem was solved by building with mvn clean install.
So, as usual, the error message was spot on - the method indeed did not exist in the version of the JAR that Jetty was being supplied.

Implement logging with AOP and Log4J

I try to add automatic logging using aspects to my web app which is developed with Java EE and Spring (core + mvc + security...). Dependencies are managed by maven and the application server is a Glassfish server. The aspect part seems to work but the logging file doesn't get the logs I send through the aspect.
I set the logging configuration in my web.xml adding this:
<listener id="myLogger">
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
The property file is the following (and it works because the log file is well created in my system folders) :
# Root logger option
log4j.rootLogger=INFO, file
log4j.rootLogger=WARN, file
log4j.rootLogger=ERROR, file
# Direct log messages to a log file
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=C:\\Users\\chaese\\Documents\\Dev\\LogsMEANS\\logging.log
log4j.appender.file.MaxFileSize=1MB
log4j.appender.file.MaxBackupIndex=1
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
I also configured an aspect (using AspectJ) in order to log all information in case of a call to a function starting with "get". Here is the class for this aspect :
import org.apache.log4j.Logger;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
#Aspect
public class PropertyChangeTracker {
private Logger logger = Logger.getLogger(PropertyChangeTracker.getClass());
#Before("execution(String get*(..))")
public void trackCalls(){
logger.info("controller called !!");
}
}
The configuration in aspect-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:aop="http://www.springframework.org/schema/aop" xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx" 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.1.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="propertyChangeTracker" class="services.aspects.PropertyChangeTracker"> </bean>
<aop:aspectj-autoproxy>
<aop:include name="propertyChangeTracker"/>
</aop:aspectj-autoproxy>
</beans>
I tested this in the debug mode and my "trackCalls" method is called without any trouble but no information gets logged into the log file. I have the feeling there are two different loggers in my app and the one used by the PropertyChangeTracker class is not the one I want... Do you see where I set something wrong?
Thanks in advance for your help!
I am not sure, but your log4j configuration looks suspected. Try to add only log4j.rootLogger=INFO, file in log4j.properties.

Spring's #Scheduled error : Only one AsyncAnnotationBeanPostProcessor may exist within the context

I am trying Spring 3's #Scheduled annotation . Here is my configuration (app.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"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:task="http://www.springframework.org/schema/task"
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.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd
"
>
<context:component-scan base-package="destiny.web"/>
<context:annotation-config/>
// other beans
<task:annotation-driven executor="myExecutor" scheduler="myScheduler"/>
<task:executor id="myExecutor" pool-size="5"/>
<task:scheduler id="myScheduler" pool-size="10"/>
</beans>
And this is my service class :
#Service
public class ServiceImpl implements Service , Serializable
{
//other injections
#Override
#Transactional
public void timeConsumingJob()
{
try
{
Thread.sleep(10*1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
#Override
#Scheduled(cron="* * * * * ?")
public void secondly()
{
System.err.println("secondly : it is " + new Date());
}
}
It works fine when testing in my eclispe + junit , when testing a timeConsumingJob method , I can see secondly() continues outputting message secondly.
But when deployed to a container (Resin/4.0.13) , it throws :
[11-03-26 12:10:14.834] {main} org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Only one AsyncAnnotationBeanPostProcessor may exist within the context.
Offending resource: class path resource [app.xml]
at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:68)
at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:85)
at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:72)
at org.springframework.scheduling.config.AnnotationDrivenBeanDefinitionParser.parse(AnnotationDrivenBeanDefinitionParser.java:82)
I searched but seldom find similar situations , I think it is the most basic setting , but don't know why it doesn't work .
Can somebody take a look at it ? Thanks a lot !
(Spring 3.0.5 , Resin 4.0.13)
------------ updated ---------
After I dig deeper , I found the app.xml is imported by another xml. Maybe this is the reason makes task:annotation-driven not working.
Well , after re-arranging some beans' location , it is solved, but I still feel puzzled. (Because it worked fine , and other.xml needs beans in app.xml )
The application context is being initialized twice but org.springframework.scheduling.config.AnnotationDrivenBeanDefinitionParser fails registering bean ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME second time.
I encountered this problem in unit tests where #ContextConfiguration("/path/to/applicationContext.xml") was accidentally on both the parent test class and child test class (with default value of inheritLocations true).
I have faced this once after implementing our own AsyncTaskExecutor and forgetting to remove default <task:annotation-driven/>
Check if you have something like this, if yes remove one of the task.
<task:annotation-driven executor="customAsyncTaskExecutor" scheduler="taskScheduler"/>
<task:annotation-driven/>
This happens when spring parses the <task:annotation-driven/> text twice in a config XML.
For me this was happening because both applicationContext-root.xml and applicationContext-where-annotation-driven-is-specififed.xml were imported in my WEB.xml in <context-param> section.
Leaving only applicationContext-root.xml in WEB.xml solved the issue.
I had this problem when I copied applicationContext.xml and created new one called applicationContextAdditional.xml. I didn't try to find the reason, but both contained namespace
<bean ...
xmlns:task="http://www.springframework.org/schema/task"
...
xsi:schemaLocation="
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd" >
...
</bean>
when I removed the namespace from the second one my problem was solved. Maybe it helps someone.
In my case, this was caused by switching versions, thereby in the output file location there are multiple version of jars (and therefore each jar contains a AnnotationBean):
2018-02-19 13:38:44,913 [RMI TCP Connection(3)-127.0.0.1] ERROR org.springframework.web.context.ContextLoader - Context initialization failed
org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Only one ScheduledAnnotationBeanPostProcessor may exist within the context.
Offending resource: URL [jar:file:/C:/.../lib/xxx-2.0.jar!/META-INF/spring/xxx.xml]
while I'm using 1.0 in this case. So I have to manually delete C:/.../lib/xxx-2.0.jar in this location, and I'm able to see xxx-1.0.jar is also in this directory. After the manual deletion, it works normally.
I had the <task:annotation-driven/> defined twice in the context xml. Removing that worked for me.
That error, about
Only one AsyncAnnotationBeanPostProcessor may exist within the context
, can appear in one more case. I do not insist, that that must help you, maybe you really have some complicated problem, described in other posts, but no one of them helped me.
What did help, was simple
mvn clean
, for the project somehow had created some duplicated files and those caused the problem. And a simple clean had... ehm... cleaned them.
That situation, for example, can happen after a merge with a branch with a higher version of the project.

Resources