Run Spring MVC webapp with different configuration during integration tests - maven

I'm using the maven-jetty-plugin to run my Spring MVC webapp during the integration-test phase of a Maven build, and run various tests on it. At this point, I'd like to be able to switch out some of the Spring configuration, so that I can point at a different bean implementation during the integration tests. This is so that I can change which database to run against, rather than use the production connection settings.
What sort of approach should I consider? Should I attempt to use resource filtering on the servlet-context.xml file? Should I have two different configuration files? How do I get this to play nicely with the Jetty plugin?
EDIT: I'm considering using Spring's Java-based #Configuration annotations in preference to the XML servlet-context file, and switching what sort of beans I construct based on environment variables or similar, but this feels wrong as well.

I will suggest using spring profile+maven filtering:
Define a property in pom.xml which can ben overwritten via command line: -Dspring.profile.active=development
<properties>
<spring.profile.active>test</spring.profile.active>
</properties>
Add resource filtering in pom.xml. Make sure your web.xml is in directory src/main/resources.
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
Active the specific spring profile in web.xml, ${spring.profile.active} will be replaced after filtering.
<context-param>
<param-name>spring.profiles.active</param-name>
<param-value>${spring.profile.active}</param-value>
</context-param>
Define beans in spring profile
<beans profile="production">
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/datasource"/>
</beans>

Previously, I always create a profile that contains jetty-maven-plugin configurations and integration tests configurations.
But when I learned about spring-test-mvc, I switched to it because everything that you want to achieve in integration tests using jetty-maven-plugin can be achieve. Plus, you can mock the services needed (eg. authentication in different app).
So I suggest to switch to spring-test-mvc. IMHO, jetty-maven-plugin style is quite painful.

Related

Spring - Activating a controller from a dependency with no configuration

I have some individual web services written with spring boot that run individually and I want to create group projects based on needs.
Right now, the controllers are annotated with the #RestController annotation and obviously, they are working fine when the apps run individually.
But I want to convert these projects into maven dependencies, where I just pass them as dependencies and the controllers can exist by just that.
I have converted these projects into executable dependencies by adding classifier = exec.
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<classifier>exec</classifier>
</configuration>
</plugin>
On other projects with only components/services, this approach work since it is just autowiring the service class.
On the group project, I still can autowire the controllers and run the functions which is okay. But those controller classes have #RestController and #RequestMapping annotations and I was wondering if it is possible to activate those controllers without doing anything?
Like just add the dependency and the controllers of that dependency are there.

Maven resource filtering - Spring application

I'm just wondering, at what point does the Maven resource filtering mechanism inject values from a profile into a target file? I'm asking because my application is using Spring, and depending on a JVM property, it will call one of my apps environment files which is in turn used to supply configuration information to spring beans as they get created.
I would like to move passwords and db type info from the environment file into the Maven Settings.xml file however I'm wondering will Spring overwrite or conflict with the way Maven resource filtering is working?
The goal is for Spring to decide what environment the application is running in and choose an environment file which will have already had the necessary values injected by Maven.
Thanks
Maven replaces placeholders within the process-resources phase. See http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html
So when spring starts creating its context the values are there.
You can use the PropertyPlaceholderConfigurer to read a properties file and make them available in the spring context:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>file://${config.dir}/external-config.properties</value>
</list>
</property>
</bean>
"config.dir" is in the system properties: java -Dconfig.dir=/dir/ or i think it can be a context parameter as well.
within the spring context ${key} from the properties file can be used to configure beans. Depending on the version of spring also annotations are available. Or there is a namespace for the PropertyResolver too.
So maven filtering and spring work nicely together.

Spring approach for changing configuration source by environment

I'm new to Spring and trying to figure out the best way to handle the following scenario:
We have an application where for local development and testing, all configuration values are pulled from a Properties file. When the app is deployed on to the App Server (Websphere in this case), instead of properties file we use JNDI resource properties.
Is there an accepted way of handling this in Spring? For a non-Spring application I probably would have done something like this using a good ol' factory pattern to decide the config source. For Spring, I've seen examples that use different context XML files per environment (sounds messy), or make use of Spring "Profiles".
Is there a generally accepted practice for this scenario?
Spring profiles are rather new and they were added precisely to address your problems. Moreover they should deprecate all other workarounds like different context XML files you mention.
For the sake of completeness here is an example:
<beans profile="test">
<context:property-placeholder location="/foo/bar/buzz.properties" />
</beans>
<beans profile="prd">
<jee:jndi-lookup id="properties" jndi-name="foo/bar/name"/>
</beans>
Depending on which profile you choose during deployment/startup, only one of the beans above will be instantiated.
Another approach I've never tried but seems to fit your case is default-value attribute in jee namespace:
<jee:jndi-lookup id="properties" jndi-name="foo/bar/name" resource-ref="true"
default-value="classpath:foo.properties"/>
Not sure if this will help you though.
Assuming Spring 3.1, try using profiles like Tomasz suggested, but instead of setting individual JNDI values for production, use
<beans profile="prd">
<context:property-placeholder/>
</beans>
In Spring 3.1, ContextLoaderListener apparently pulls in JNDI props as a PropertySource by default, so with property-placeholder, when you need to access a value you can just use ${some/jndi/name} in applicationContext.xml or a #Value annotation.
To make sure the webapp gets the values from JNDI, add
<context-param>
<param-name>spring.profiles.default</param-name>
<param-value>prd</param-value>
</context-param>
to web.xml.
In your tests, set the system property 'spring.profiles.active' to 'test', and you'll get the values from the props file.
one way to go is you use jndi also for local dev and testing. You could define the same jndi name. I don't know what's your testing server, in practice we use jetty, and maven-jetty plugin to test. It is lightweight and can run from your ide.
another way is like what you said in your question. Making use of Spring profile. Then you could declare different transactionManager beans with same id/name. of course they should be in different profiles. At runtime you could decide which profile should be activated, that is, which bean should be used.

Dealing with two different values of a property (cloud and default) in cloudfoundry and the #Value annotation

I am in reference to Spring's #Value annotation as documented here: #Value and Spring profiles.
I need to be able to have different values for a given property such as:
websiteContext=http://localhost:8080/kadjoukor
...according to whether the app is running locally or on the cloud. I am not sure how to achieve that with the #Value("${websiteContext}") annotation...
What is the best practice for dealing with such an issue?
If you are using Spring 3.1 or later, you can take advantage of bean profiles and the CloudFoundry "cloud" profile to load a different properties file depending on the environment. That might look something like this in a Spring XML configuration file:
<beans profile="default">
<context:property-placeholder location="default.properties"/>
</beans>
<beans profile="cloud">
<context:property-placeholder location="cloud.properties"/>
</beans>
Here are a few good blog posts that explain how this works in more detail:
SPRING 3.1 M1: UNIFIED PROPERTY MANAGEMENT
USING CLOUD FOUNDRY SERVICES WITH SPRING: PART 4 – SPRING PROFILES

JUnit: how to access Spring configuration as Spring has intended?

There is a tutorial video that introduces Spring MVC 3.0. In the demo-project they use the following directory structure:
<proj>
src
main
webapp
WEB-INF
spring
appServlet
controllers.xml
servlet-context.xml
root-context.xml
Let's say I have a project with Maven-support and I want to write JUnit tests using Spring's configuration. Currently we use JUnit 4.8.2. This would obviously require to load the three files listed above.
In the test I could use annotations like
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath*:/WEB-INF/spring/**/*.xml")
However, that doesn't find the XML-files. I took a look at the classpath and noticed, that only the <proj>/target/classes and <proj>/target/test-classes are included by default.
One obvious solution would be to add the proper path to the classpath, but I don't know if that is what the guys at Spring had in mind.
Therefore, my question: What do I need to do to load the configuration files while letting it look as if I'm the total pro-coder using Spring?
Another option is to use file system resource loader:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
You should put the "normal" spring configuration in the resources folder but not in the webapp folder: src\main\ressources\WEB-INF\spring\root/spring-context.xml. Then you can access it without problems from the test.
Put only the web related spring configuration (servlet-context.xml) in the webapp folder.
The structure that you described is the one generated by the STS-Spring-Template:MVC-Template, however Spring-ROO and Spring-Fuse generate the structure that I have described.
For example Spring ROO:
<project>/src/main/resources/META-INF/spring/applicationContext.xml
<project>/src/main/webapp/WEB-INF/spring/webmvc-config.xml
<project>/src/main/webapp/WEB-INF/web.xml
web.xml:
...
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:META-INF/spring/applicationContext*.xml</param-value>
</context-param>

Resources