How to Setup web application context in Spring MVC test - spring

We have a clear abstraction between Service layers & view layers context configurations and we are loading them as shown below.
Root application context:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:META-INF/spring/applicationContext*.xml</param-value>
</context-param>
Web application context:
<servlet>
<servlet-name>lovemytasks</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/mmapp-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Now we are trying to introduce SPRING MVC TEST FRAMEWORK to test our application.
For this i would need to setup the same environment as my real web application works.
How can i do that ?
I tried below configuration on my test to load both the contexts.
#ContextConfiguration(locations = { "classpath*:META-INF/spring/applicationContext*.xml",
"file:src/main/webapp/WEB-INF/spring/mmapp-servlet.xml" })
But its erroring out saying
Caused by: org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Duplicate <global-method-security> detected.
We have defined global security in both root application context and web application context.
Note: The above said issue will not appear when i run my web application. It happens only when i run Spring MVc test
I tried removing my global security and one place and then landing into errors with conversion services on running my tests. Which warned me that I am not loading the context as teh real Spring application does.
Now, i would like to setup my Spring MVC test environment to use or work as the same way my spring web application environment works. Can any one please suggest how can i achieve it ?

Use the #ContextHierarchy annotation. Its javadoc describes it well. In your case you would use
#WebAppConfiguration
#ContextHierarchy({
#ContextConfiguration(locations = { "classpath*:/META-INF/spring/applicationContext-*.xml" }),
#ContextConfiguration(locations = { "file:src/main/webapp/WEB-INF/spring/mmapp-servlet.xml" })
})

don't put your appContext in meta-inf.
The "normal" way is to have one spring-servlet.xml in your web-inf
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/spring-servlet.xml</param-value>
</context-param>
Andn then import different files within the xml file :
<import resource="classpath:beans.xml"/>
I create a seprate appContent for my tests :
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations ="classpath:applicationContext-test.xml")
#Transactional
public class MyTest {
Your beans must be getting loaded twice somewhere along the line, are you importing the beans twice, defining them both in xml and also annotating ?

Related

Spring Data REST with Spring MVC: Adding RepositoryRestMvcConfiguration to existing DispatcherServlet

I have an existing Spring MVC Application with a DispatcherServlet and an XML based configuration.
Now I would like to integrate Spring Data REST but I dont know how to do this in a clean way. I added
<context:component-scan>...</context:component-scan>
so my RestControllers are found but I fail in adding a RepositoryRestMvcConfiguration config. I tried the annotation driven approach which doesnt work
#Configuration
public class RestConfiguration extends RepositoryRestMvcConfiguration {
...
}
and the
<bean class="com.mypackage.rest.RestConfiguration" />
approach is not working either.
I also tried the follwing in the web.xml
<servlet>
<servlet-name>myservlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.mypackage.rest.RestConfiguration</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Strange thing is, a method annotated with #PostConstruct is called, but non of the configure* methods.
In the docs for Spring Data REST is a chapter where it is explained how to add a Spring Data REST to a Spring MVC application in code. It also says
The equivalent of the above in a standard web.xml will also work identically to this configuration if you are still in a servlet 2.5 environment.
How do you do this?
Fortunately, in Section 11.2 it is explained. Would have been nice to have a reference in Section 2.5 that points to Section 11.2 :-/
In Java, this would look like:
import org.springframework.context.annotation.Import;
import org.springframework.data.rest.webmvc.RepositoryRestMvcConfiguration;
#Configuration
#Import(RepositoryRestMvConfiguration.class)
public class MyApplicationConfiguration {
…
}
In XML this would look like:
<bean class="org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration"/>

OpenEntityManagerInViewFilter not working - Spring MVC

Ok, so I am once again going nuts trying to solve the OpenEntityManagerInViewFilter problem.
I have looked around a bunch, read a lot of the other questions (that this might seem like a duplicate of) but no joy so far.
So here's the deal: Spring4, XML based web.xml but java vconfig for the rest of my app context setup. I thought it might be related to this solution: https://stackoverflow.com/a/7015927/258813 (the ContextLoadListener and the servlet config both loading the app contexts), however, I have ensured that they both explicitly reference different configuration files. I have also previously had problems when different config files were #ComponentScan-ing the same locations so the context was loaded twice, but that is not the case either.
Web.xml (relevant bits)
<servlet>
<servlet-name>webapp</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.tmm.frm.configuration.WebMvcConfiguration</param-value>
</init-param>
</servlet>
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
com.tmm.frm.configuration.ApiSecurityConfig
com.tmm.frm.configuration.ApplicationContextConfiguration
com.tmm.frm.configuration.WebSecurityConfig
</param-value>
</context-param>
The security configs are both just standard WebSecurityConfigurerAdapter extensions, no other scanning/context jazz.
WebMvc config:
#Configuration
#EnableWebMvc
#ComponentScan("com.tmm.frm.controller")
public class WebMvcConfiguration extends WebMvcConfigurerAdapter{
App Context Config (persistence stuff etc)
#Configuration
#EnableTransactionManagement(mode = AdviceMode.ASPECTJ, proxyTargetClass = true)
#ComponentScan({"com.tmm.frm.service", "com.tmm.frm.helper","com.tmm.frm.core.dao", "com.tmm.frm.security"})
#PropertySource("classpath:META-INF/spring/database.properties")
#EnableAspectJAutoProxy(proxyTargetClass = true)
public class ApplicationContextConfiguration {
So both the relevant config classes are specifically defining different packages etc. Web.xml names configs to load by name so neither config classes are being loaded twice.
Then, I hit the controller - I load the user profile from the Secuirty Context (in the controller), then I jsut try to loop through a collection on the UserProfile that is lazily loaded - I would expect the OpenEntityManagerInViewFilter to kick in and load the collection (as a session is still open) but I get the normal can't load lazy object error. The logs clearly states that the filter is called, so I assume somewhere there are two contexts - any one suggest where the rogue context might be?
From what you have said, you are loading the UserProfile from the security context, presumably you have loaded up the security context at user login.
Now, the EntityManagerthat you used to load up the UserProfile at login to load up the SecurityContext is definitely not going to be valid for a new request coming into system past the login and hence the error. The scope is tied to one web request scope.
The only good workaround that I would see is to only keep some identifier of the user in the securitycontext and load up the actual user details when you need additional details or store initially with additional details.

EnableLoadTimeWeaving did not weave other config in web application context

I try to use spring weblogic LTW in my project to do some aop stuff. my project is a simple webapp servlet2.5 use spring mvc 3.2.6, running on weblogic 10.0.
I have following app level configuration setup in web.xml
#Configuration
#EnableLoadTimeWeaving
public class AppConfig {
}
#Configuration
#EnableTransactionManagement
#ComponentScan(basePackages = { "com.blabla.model" })
public class CoreConfig {
}
I also have a mvc level configuration setup in my web.xml
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = { "com.blabla.controller" })
public class MVCConfig extends WebMvcConfigurerAdapter {
}
here is my simplified web.xml
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>AppConfig,CoreConfig
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>MVCConfig
</param-value>
</init-param>
<init-param>
<param-name>wl-dispatch-policy</param-name>
<param-value>RestWorkManager</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
so what happens is, MVCConfig and its scanned components are all woven by LTW and works great. but CoreConfig and its scanned components (all the DAO) are not picked up by LTW.
I guess that the CoreConfig and AppConfig is in the same level, so when AppConfig and CoreConfig are loaded, the LTW is not triggered yet.
And I tried to put the CoreConfig in the same level as MVCConfig, it got picked up by LTW.
but CoreConfig is supposed to be application level, not dispatchservlet level. Since many spring web MVC applications use a root context and a child for the DispatcherServlet.
so My question is if I put CoreConfig in the app level, how to make LTW pick it up? Thanks.
Loadtimeweaving will only work for classes that aren't already loaded by the class loader.
Now when using XML configuration the actual bean classes are loaded after the load time weaving is enabled so it works, more or less, flawlessly for all classes.
With Java Config classes are loaded as soon as the #Configuration annotationed class is loaded. All classes that are imported are loaded into the class loader. After this load time weaving is enabled, however only for classes that are going to be loaded after this point.
Hence the fact that it is working for classes loaded by the configuration as specified for the DispatcherServlet and hence the problem in the ContextLoaderListener.
One thing you can try is to put a #ComponentScan for #Configuration classes on the AppConfig. And let the ContextLoaderListener only load the AppConfig. That might defer the class loading a little until after the load time weaving is enabled.
Something that definitely will work is putting both configuration classes in XML, remove the #EnableLoadTimeWeaving for the AppConfig and use a <context:load-time-weaving />.

About multiple containers in spring framework

In a typical Spring MVC project there two "containers": One created by ContextLoaderListener and the other created by DispatchServlet.
I want to know, are these really two IoC container instance?( I see two bean config files, one is root-context.xml the other is servlet-context.xml)
If there are 2 containers, then what's the relationship?
Can the beans declared in one container be used in the other?
From the Spring Official Website:
The interface org.springframework.context.ApplicationContext
represents the Spring IoC container and is responsible for
instantiating, configuring, and assembling the aforementioned beans.
The container gets its instructions on what objects to instantiate,
configure, and assemble by reading configuration metadata. The
configuration metadata is represented in XML, Java annotations, or
Java code.
Again from official Doc:
In the Web MVC framework, each DispatcherServlet has its own
WebApplicationContext, which inherits all the beans already defined in
the root WebApplicationContext. These inherited beans can be
overridden in the servlet-specific scope, and you can define new
scope-specific beans local to a given Servlet instance.
Now coming to your Question, as is stated here:
In Spring Web Applications, there are two types of container, each of
which is configured and initialized differently. One is the
“Application Context” and the other is the “Web Application Context”.
Lets first talk about the “Application Context”. Application Context
is the container initialized by a ContextLoaderListener or
ContextLoaderServlet defined in the web.xml and the configuration
would look something like this:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:*-context.xml</param-value>
</context-param>
In the above configuration, I am asking spring to load all files from
the classpath that match *-context.xml and create an Application
Context from it. This context might, for instance, contain components
such as middle-tier transactional services, data access objects, or
other objects that you might want to use (and re-use) across the
application. There will be one application context per application.
The other context is the “WebApplicationContext” which is the child
context of the application context. Each DispatcherServlet defined in
a Spring web application will have an associated
WebApplicationContext. The initialization of the WebApplicationContext
happens like this:
<servlet>
<servlet-name>platform-services</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:platform-services-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
You provide the name of the spring configuration file as a servlet
initialization parameter. What is important to remember here is that
the name of the XML must be of the form -servlet. xml.
In this example, the name of the servlet is platform-services
therefore the name of our XML must be platform-service-servlet.xml.
Whatever beans are available in the ApplicationContext can be referred
to from each WebApplicationContext. It is a best practice to keep a
clear separation between middle-tier services such as business logic
components and data access classes (that are typically defined in the
ApplicationContext) and web- related components such as controllers
and view resolvers (that are defined in the WebApplicationContext per
Dispatcher Servlet).
Check these links
Difference between applicationContext.xml and spring-servlet.xml in Spring Framework
http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/beans.html#beans-basics
There aren't two separate containers created. Typically, you want spring to instantiate the object declared in the servlet-context.xml when the object is required. So, you map the servlet-context.xml configuration file to the Dispatcher Servlet i.e. you want to initialize the object when a request hits the dispatcher servlet.
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Where as, if you want to initialize the object and perform action when the context is being loaded you would declare the configuration file with in the context-param tags of your deployment descriptor.
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
You could test this out by writing by declaring separate beans in the servlet-context.xml and root-context.xml and then, autowiring them in a custom Context Loader Listener class. You would find only the root-context instances are initialized and servlet-context beans are null.
ApplicationContext a registry of components (beans).
ApplicationContext defines the beans that are shared among all the servlets i.e. root context configuration for every web application.
spring*-servlet.xml defines the beans that are related WebApplicationContexts here DispatcherServlet.
Spring container can have either single or multiple WebApplicationContexts.
Spring MVC have atleast 2 container -
Application Context declared by
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
Servlet context declared by -
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
And a web application can define any number of DispatcherServlet's. Each servlet will operate in its own namespace, loading its own application context with mappings, handlers, etc. Only the root application context as loaded by ContextLoaderListener, if any, will be shared. Thus can have any number of child containers.

Spring: link between WebApplicationContext and ApplicationContext?

I am working on a Spring application. I started from creating a small java app using spring. Later, it became necessary to add a web interface. I decided to use Spring MVC. Now I am confused. In my web.xml I have
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/mvc-dispatcher-servlet.xml,
/WEB-INF/applicationContext.xml
</param-value>
</context-param>
where mvc-dispacher-servlet.xml contains beans necessary for web logic while applicationContext.xml contains beans performing some specific operations. My question is: Are beans in these files going to be aware of each other? Is it going to be a one big container which includes beans from both config files? or these containers are separate?
Yes it will be in one context which will be loaded from the web application context. Its the same as you would do when using the application context and passing in multiple files to it.

Resources