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

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>

Related

Is it possible to use Spring boot with web.xml and annotation based configurataion

I want to use Spring Boot with web.xml and servlet 3.1 configuration.Is there any example?
I want to define my context(Dispatcher servlet/SpringBootServletInitializer) in Web.xml mean time define all other configuration using annotation based.Ex want to load application.properties/yml values using pojos.
Need this type of configuration to deploy the app in Liberty profile as Liberty expecting application context in web.xml when using liberety global sharelib.

Maven created Spring web project, but only worked if I deployed its war to Tomcat, and Failed when startup in Eclipse

I am using spring version 4.1.1.RELEASE with junit version 4.11
I created a Maven with type "maven-archetype-webapp"
Before using junit I put spring-servlet.xml within webapp/WEB-INF/. This config works well for Tomcat web container, but Junit cannot refer to this context file because junit's awareness of classpath does not include webapp/WEB-INF/.
In order for junit to be able to read the context configuration for spring, I had to put spring's servlet config file at: src/main/resources/config/spring-servlet.xml . Maven will copy this file into /target//WEB-INF/classes/config/spring-servlet.xml
In order for this config to work for both JUnit and Tomcat web container , I have to made below modification
For Junit:
1> Using Annotation to inform junit about the location of file "spring-servlet.xml"
#ContextConfiguration({ "classpath:config/spring-servlet.xml" })
public class AnotherTest { ... }
For Tomcat deployment:
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:config/spring-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
And things work well for both junit and tomcat deployment.
But from some sources, they said that using "classpath:" would cause confuse about context in some cases (I don't know which cases?)
And they suggest we should use below config (namely option2) instead , to avoid using "classpath:"
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/classes/config/spring-servlet.xml</param-value> <!-- this config does not use classpath -->
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
With option2 , junit works fine. But running this web project within eclipse would cause FileNotFoundException at the startup time of tomcat because tomcat container does not see spring-servlet.xml . Of course I had executed Maven clean & build and ensure that war had been created, I also inspect and see /target//WEB-INF/classes/config/spring-servlet.xml had been created, Java classes had been compiled, before I execute Maven to start Tomcat.
I found out that, if I copy war file created by Maven, and manually deploy this war into Tomcat then everything work fine.
I doubt that, Maven with Eclipse some how, does not generate WEB-INF/classes/config/spring-servlet.xml properly at the time Maven start Tomcat. At least, I think Maven and Eclipse does not simply using what had been built (i.e project's java class and other resources) to run/deploy with Tomcat.
Is there anyway that I can use the config at option2 above to develop within Eclipse to start Tomcat, and to execute Junit properly?
Or is there any other better way (e.g another directory) to store and config file spring-servlet.xml , please explain.
Thank you.
There can be many ways to achieve and here is one of the way which I follow to avoid this type of situations.
I hope the same custom directory structure given by maven is followed.
Project
Module
src
main
Java
resources
webapp
test
Java
resources
Here are couple of options that we do.
Accessing the context XML file using classpath*:
for the test cases in #ContextConfiguration which will be access from main/resources
for the reference in web.xml, context file will be in main/resources
Writing a separate context file for the junit tests
But from some sources, they said that using "classpath:" would cause confuse about context in some cases (I don't know which cases?)
confusing the context ? Seriously ?
Most of the cases, using classpath* will give access to all the files in the execution. Here might be the case where name is same for multiple jars, though I haven't encountered that any point of time.
Another context file for Junit under test/resources
This enables the flexibility of making changes to the environment that we use for testing.
For instance
mocking beans
Configuring derby database for mock scenarios
Accessing the generated classes is not preferable method even though internal access will happen.
And I believe here, there is nothing to do with the version of the spring/junit. Its all about accessing the context file from different perspectives.

How to do Spring context initialisation from a dependency library within a web application?

I have a web application which uses Spring. Bean definitions and spring configuration for the web application are declared in webapp-spring.xml. This web application uses a library as its dependency. Let us say the library is called data-access.jar. This library is on the web application's classpath. The web application is configured to initialise spring context by the usual web.xml configuration:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:webapp-spring.xml</param-value>
</context-param>
The data-access.jar library also has its own spring beans xml definition data-access-spring.xml embedded within it (directly at the root level) for its internal use of Spring dependency injection.
When the web application context initialisation happens on starting the container (Tomcat), I would like Spring to initialise context using data-access-spring.xml along with web-app-spring.xml. How do I do this?
I tried following which didn't work:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:web-app-spring.xml,classpath*:data-access-spring.xml</param-value>
</context-param>
Spring silently ignores data-access-spring.xml and only initialises the bean definitions from web-app-spring.xml.
classpath*: will basically ignore files which don't match the pattern. But your syntax is correct. So it looks like data-access-spring.xml isn't being found. Are you sure it's at the root?
You could also use patterns, btw, e.g. classpath*:*-spring.xml, but that shouldn't help you here. classpath*:web-app-spring.xml,classpath*:**/data-access-spring.xml might if it's not at the root.

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.

Where do Spring bean configuration files go in a Maven WAR module?

I've looked at a bunch of sample projects and I can't seem to tease out a common best practice. I've seen Spring bean config files sometimes go in the src/main/webapp/WEB-INF directory. I've seen this in conjunction with with a Servlet definition in web.xml like this:
<servlet>
<servlet-name>my-stuff</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/my-stuff-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
But I've also seen bean config files included within web.xml top level -- i.e. outside of a Servlet. What does this mean? Is this for cross-Servlet beans? Sometimes it's in the src/main/webapp/WEB-INF directory and sometimes it's in src/main/resources. Also I've seen other bean config files defined in WAR modules with just about everything in src/main/resources.
I've read and re-read the Spring documentation, but the only convention I found is that by default a Servlet context config file should be in the src/main/webapp/WEB-INF directory named {servlet-name}-servlet.xml.
So what's the best practice and why?
Application contexts in Spring can form hierarchies where child context has access to beans defined in parent context.
A typical Spring MVC web application contains a hierarchy with two levels:
Root web application context loaded by ContextLoaderListener.
Config location of this context is applicationContext.xml by default and can be configured using <context-param> named contextConfigLocation, i.e. at the top level of web.xml. This context usually contains a core application logic.
Servlet-specifc context loaded by DispatcherServlet. Its config location is by default <servletname>-servlet.xml and can be configured using <init-param> named contextConfigLocation, i.e. at servlet level. This context usually contains a Spring MVC-related stuff (controllers, etc) since DispatcherServlet is a part of Spring MVC.
The latter context is a child of the former.
If web application doesn't use Spring MVC as a presentation framework, it doesn't have DispatcherServlet and its context. Some extremely simple Spring MVC samples doesn't have ContextLoaderListener and the root context (however, you need root context for cross-servlet functionality such as Spring Security).
Config files of web application are by default located in webapp's root folder. However, they can be placed in the classpath (i.e. in src/main/webapp), in this case they are accessed via classpath: prefix. This may be useful if you are going to use some of these files in integration tests without servlet container. Also classpath: prefix may be useful when you want to load a config file from a separate artifact, i.e. from a jar file in /WEB-INF/lib.
I think it is often good style to keep the code, its spring configuration an in a separate JAR that is included into the WAR, such that the WAR is basically empty but for web.xml and the like. This saves you from even asking this question. :-) You can reference those spring configurations with classpath: prefix.
One advantage of this layout is that you can easily write Unittests that instantiate the complete Spring configuration of the WAR within the JAR. I would not necessarily recommend to use this for actual tests (although you can do integration tests this way), but you get a quick feedback when you accidentially break the overall structure of the config files without having to redeploy the application.
If you really need to put spring configuration files into the WAR (perhaps since it also references beans that are implemented in the WAR itself) I would also put them into the normal resources path /WEB-INF/classes, for the reasons discussed above.

Resources