how to define contextParameter in Spring - spring

I am working on a web project and I defined some properties in the context.xml of my Tomcat, like path, properties value for the configuration of the application.
My problem arrives when I want to write some JUnit tests, which are launched outside my web container, how can I define these parameters?
To be clear, in my context.xml (in Tomcat configuration directory), I have:
<Parameter name="myProperty" value="myValue" override="false"/>
And with Spring, I access it with:
<property name="property" value="#{myProperty}" />
But when I launch a junit test, the context.xml is not loaded, I need another way to define the property.
How can I do that?
To be more precise, the context.xml file which we are talking about is a file used by my Tomcat server, it does not follow the Spring schema and I think that I can't "import" it into Spring.
I already use the SpringJUnit4ClassRunner and the ContextConfiguration tag, it works fine, but now, I need to emulate/replace the Tomcat's behaviour to define this ContextParameters and retrieve my parameter...
I hope I am clearer :)

Try using something like this :
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath:context.xml")
public class MyTestClass {
//put tests here
}
EDIT:
You can also specify a path to the context file :
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("file:src/main/resources/spring/config.xml")
public class MyTestClass {
//put tests here
}

For the suggestion above to work, you need to depend on the spring-test module.
You can also load your context file the good old fashion way.
ApplicationContext context = new ClassPathXmlApplicationContext("context.xml")
And then grab your bean by name.

Related

Can I start with a spring boot application without the annotations componentscan,autoconfiguration,configuration,springbootapplication?

I have written some code in order test integration with mongoDB. Please find the link to the main method for running this spring boot application below,
https://github.com/siva54/simpleusercontrol/blob/master/src/main/java/com/siva/UserManagementApplication.java
From what I have read, An application should contain any of the configurations from the following URL to declare how the applications manages the context,
http://docs.spring.io/autorepo/docs/spring-boot/current/reference/html/using-boot-using-springbootapplication-annotation.html
I haven't used any of those contexts, However my application works fine and I'm able to run it without any issues. Am I missing something here? Can you please help with the info of how my application is able to start and manage the context/dependencies automatically?
Thanks in advance
#SpringBootApplication is equivalent of #Configuration, #EnableAutoConfiguration and #ComponentScan. Let's consider why your application works without of any of this three annotations.
Why it works without #Configuration:
When Spring will scan packages, it will find all classes marked by #Configuration and will use them as part of configuration. But in next line you manually passed UserManagementApplication as configuration source:
SpringApplication.run(UserManagementApplication.class, args);
So spring doesn't need to find this class by scan. Therefor it is not necessary to mark it by #Configuration.
Why it works without #ComponentScan:
Class UserManagementApplication has #ImportResource("classpath:spring/application-context.xml") annotation. That means file spring/application-context.xml will be included into configuration. And this file contains next line:
<context:component-scan base-package="com.siva.*" />
So, you don't need use annotation for scan packages, because you already declared it in the xml file.
Why it works without #EnableAutoConfiguration:
This annotation allows to Spring to try guess and configure the components automatically. For example, if you include the following dependency in your build.gradle:
dependencies {
compile 'org.springframework.boot:spring-boot-starter-data-mongodb'
}
Spring configures all the components required to work with MongoDB automatically. And all you need just specify host and user/pass in the aplication.proprties file.
But you preferred to declare all needed beans manually in the spring/application-context.xml file. So, you simply don't need #EnableAutoConfiguration annotation at all.

removing singleton beans from context during the test

I have an application written using spring-REST(spring version 4.1.x and am using spring test for testing it. One of the singleton bean is caching the state so that it can be used for subsequent call in the application. This is although causing the problem when I am running multiple tests as the same bean is being used across tests and subsequent test fails. My question is how do I reset the state in the teardown?
State is not accessible as its a private member of the class. Can we just remove the bean completely from the context? I am using annotated beans and autowiring wherever required.
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration(classes = ComponentTestConfig.class)
public class WebServiceComponentTest {
}
I tried to use the solution given in the following link
How can i remove a singleton spring bean from ApplicationContext?
but always faiuls with no bean definition found
((BeanDefinitionRegistry) beanFactory).removeBeanDefinition("myBean");
By the way test fails only when teardown called for resetting the bean state. Bean is found while it is being used by application.
If you want more fine-grained control over your testing application context, mirror your XML config files for testing. Point your test class to only load the XML files from your test directory rather than from your WebContent directory.
That way you can totally exclude the class that is causing you problems from your test context. So your test XML might look something like this:
<context:component-scan base-package =
"au.com.foo.pineapple",
"au.com.foo.dolphin",
"au.com.foo.controllers"
/>
<!--au.com.foo.building-->
and your WebContent XML file might look something like this:
<context:component-scan base-package =
"au.com.foo.pineapple",
"au.com.foo.dolphin",
"au.com.foo.building",
"au.com.foo.controllers"
/>
As M. Deinum pointed out, the safest way to achieve this is to use the #DirtiesContext annotation.
However, as also mentioned, using #DirtiesContext can result in longer test runs since the ApplicationContext will be removed from the ContextCache.
Another option -- a hack really -- is to use the ReflectionTestUtils class from spring-test to change the state of the private member in question.
Regards,
Sam (author of the Spring TestContext Framework)

#Autowired in bean not in spring context

I am new to springs. Is there an alternative for autowired to be used in a ordinary java bean which is not present in spring context.
You can do so by using Spring #Configurable with some AspectJ magic.
If you need a detailed explanation, here is the link.
And here is a brief overview of how it can be achieved.
First you have some bean that you want injected somewhere:
#Component
public class InjectedClass {
// ...
}
Then, you have a class that is not spring-container managed, that you want to instantiate. You want autowiring to work with this class. You mark it as a #Configurable.
#Configurable
public class NonContainerManagedClass {
#Autowired
private InjectedClass injected;
// ...
}
Now you need to tell spring that you want this non-container managed autowiring to work. So you put the following in your spring configuration.
<context:load-time-weaver />
<context:spring-configured />
Now, since this kind of thing requires modification of the bytecodes of your #Configurable class. So you tell Tomcat to use a different classloader. You can do so by creating a context.xml in your application's META-INF diretory and putting the following in there.
<Context path="/youWebAppName">
<Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"
useSystemClassLoaderAsParent="false"/>
</Context>
Now, Tomcat needs to find that classloader. You can ensure that by putting Spring's spring-tomcat-weaver.jar (probably named org.springframework.instrument.tomcat-<version>.jar) in your tomcat installation's lib directory, and voila, the aspectj magic starts working. For classes that are annotated with #Configurable annotation, the #Autowired dependencies are resolved automatically; even if the instances are created outside of the spring-container.
This is probably the only way to make that work with Spring, in a clean manner. Make sure that you have appropriate dependencies in your classpath.
Another way would be to use the full AspectJ functionality and providing custom aspects around all your constructors and handling the dependency-injection yourself.

spring testing: Another CacheManager with same name 'myCacheManager' already exists in the same VM

Before you mark this as duplicate please read the question first. I've read all the stuff about this exception however it does not solve the issue for me. And I do get a slightly different exception eg Another CacheManager with same name 'myCacheManager' already exists instead of Another unnamed CacheManager already exists.
Spring config:
<cache:annotation-driven cache-manager="cacheManager"/>
<bean id="cacheManager"
class="org.springframework.cache.ehcache.EhCacheCacheManager"
p:cacheManager-ref="ehcache"/>
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
p:configLocation="ehcache.xml"
p:cacheManagerName="myCacheManager"
p:shared="true"/>
ehcache
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
updateCheck="false" name="myCacheManager">
</ehcache>
The Problem is that I have 1 (in the future more) test classes that test security. these classes also load a SecurityContext.xml
So most test classes have this annotations:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath:ApplicationContext.xml")
However the class causing the issue:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {
"classpath:ApplicationContext.xml",
"classpath:SecurityContext.xml"
})
It seems since locations are different the context is loaded again but ehcacheManager is still active from previous test.
Note: this happens only when running multiple tests (eg. like clean + build). Running this test class separately works perfectly fine.
Whats the issue? How can I solve it?
Add #DirtiesContext annotation to your test class:
#ContextConfiguration(...)
#RunWith(...)
#DirtiesContext // <== add e.g. on class level
public class MyTest {
// ...
}
This annotation indicates that the application context associated with a test is dirty and should be closed. Subsequent tests will be supplied a new context. Works on class-level and method-level.
I don't know if the question/issue are still relevent, but here's a simple/proper solution (Don't need to add #DirtiesContext in all your tests). Avoid #DirtiesContext allows you to have only one shared context for all integration tests (via run by maven for example, or run all tests in an IDE). That avoids multiple problems caused by multiple contexts started in same times.
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
p:configLocation="ehcache.xml"
p:cacheManagerName="myCacheManager"
p:shared="${ehcacheManager.shared:true}"
p:acceptExisting:"${ehcacheManager.acceptExisting:false}"/>
In your tests (integration tests), set those properties
ehcacheManager.acceptExisting=true
ehcacheManager.shared=false
It allows Spring to create an EhcacheManager (ehcache) for each test, but if an
EhcacheManager with the same name exist, Spring will just reuse it. And Spring will also not destroy/shutdown it in the context annotated with #DirtiesContext.
The idea is simple, you prevent the destroy of EhcacheManager when using #DirtiesContext.
It's applicable if you use Spring 4 and EhCache:2.5+. With Spring 3, you must an extends of EhCacheManagerFactoryBean to add these two properties.
Don't forget to clear your cache before each test :)
You can run your tests with caching disabled even if your code has methods with #Cacheable annotations.
That way you do not have to slow your test run down by marking all of your tests with #DirtiesContext.
Put the cache related Spring configurations in their own Spring config file, eg. applicationContext-cache.xml file.
Include that applicationContext-cache.xml file only when running the application live, but not in your tests.
If you specifically want to test caching, then you need the #DirtiesContext annotation.
This happens because during testing, there are ultiple Spring application contexts existing at the same time. However, ehcache is JVM-global.
You can essentially disable Spring context caching, by creating spring.properties file on your classpath:
spring.test.context.cache.maxSize=1
Make sure that the cache manager is properly unregistered when a context is destroyed.
This solved my testing issue:
spring.cache.type=none
Slightly longer version:
Julien Dubois:
I would just do spring.cache.type=none as:
it's much simpler
it would work as in the previous versions
I prefer to have the cache disabled when I do my tests - then of
course there could be a very long discussion here - so that's also my
favorite solution.
Detailed version (not exactly same, but similar issue):
Read this.

Spring: <util:properties> ignored in JUnit environment?

In my Spring servlet configuration (lets call it service-servlet.xml) I am loading properties from a file:
<util:properties id="ServiceProperties" location="classpath:service.properties" />
And then later autowiring them in my service class:
#Value("#{ServiceProperties['my.property']}")
private Integer myProp;
This works fine and service runs with no problems when deployed under Glassfish.
Now I am writing a test class for my service, and running it with SpringJUnit4ClassRunner:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration({
"classpath:service-test-servlet.xml",
"classpath:service-test-context.xml"
})
public class ServiceTest {
// ...
}
So in service-test-servlet.xml, which is a copy of service-servlet.xml with few minor adjustments for testing environment, I do include the properties file the same way, but seems it is simply ignored...
First, I thought, I may be that my file is not found or so, but then even if I intentionally enter wrong name - it just ignores it and goes further with crashes at some later point because there is no bean named "ServiceProperties" and it cannot autowire "myProp" in my service class...
Is the <util:properties> being totally ignored in JUnit environment?

Resources