I'm new to Spring and am using an existing Spring library/api. All beans are configured in java classes, ie. no xml, and the existing configuration comes with one line in the main method:
SpringApplication.run(ServerExchange.class, args);
The library deals with the protocols to interface with a private server, I've been able to create normal instances of classes, ie:
AccountManager aM = new AccountManager()
however the configuration that's meant to be autowired into each class, such as the AccountManager, isn't being done as it's intended to be created as a "bean", so when I go to use the AccountManager, it's dependencies that are #Autowired are null
I've been looking online and trying to find an example of how to go from the first given line in the main method however what I can find online is mainly based around either xml or an "ApplicationContext". I'm not sure how to take the first step and simply create a bean, can anyone please provide an example of the code to create an AccountManager bean?
Thanks in advance.
Edit:
To clarify, I'm interested in the code required in the main method of how to get the instance of it once the beans have been set up in their respective classes.
If you want to configure been at class, you can do it as follow.
#Configuration
public class AppConfig {
#Bean
public AccountManager accountManager() {
return new AccountManager();
}
}
Or If you wanna use xml then
<beans>
<bean id = "accountManager" class = "packageName.AccountManager" />
</beans>
Then you can use it in a class as follows.
#Autowired
AccountManager accountManager ;
To create a bean of AccountManager do following:
#Bean
public AccountManager accountManager() {
return new AccountManager();
}
If you need any field to be autowired in an object you cannot instantiate it with new because when you do so Spring don't know about it.
You can do the following :
class MyClass{
#Autowired
ApplicationContext applicationContext;
public void method(){
AccountManager ac = applicationContext.getBean(AccountManager.class);
}
}
if your AccountManager is known by Spring. With an annotation on the class like #Component
As I'm not a user of Spring-boot in this way I found here : How to get bean using application context in spring boot how to get ApplicationContext in a different way than the one I'm using
I'm trying to learn groovy and integrating it with an existing Java jar. The java code makes use of DI but i cant seem to get it to work from my groovy script.
The Java application contains a data access layer using Mybatis. This layer consists of a number of Interfaces (e.g IUser) and Controllers
e.g.
#Service
public class UserController implements IUser
The Controllers make use of Mybatis Mapper Classes.
The whole thing is pulled together using Spring with default-autowire="byName">
Its set up to use annotations to access the mappers within the controllers.
Mybatis is configured in Spring to scan and inject the mappers
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.directski.data.mapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
So when i run my application in java everything works normally. Including any mappers i have called using
#Autowired
private UserMapper userMapper;
When i try to include this jar as part of a groovy scrip i start to run into some problems. Im using the same applicationContext file for Spring
ApplicationContext ctx = new ClassPathXmlApplicationContext("controller-layer-applicationContext.xml");
When i run as a script i can see from the logs that the components are scanned. Some of my controllers include a #PostConstruct method which gets called, and database queries are sucessfully executed. However when trying to call my controllers from my script i get null pointer errors.
I have tried using #Autowired to create my controllers in groovy but they dont seem to get injected. I have also implemented factory.registerBeanDefinition() as per examples in http://groovy.codehaus.org/Using+Spring+Factories+with+Groovy
however this does seem to get my controller to be created, but the Mybatis Mappers within my controllers are returning null
How can i make sure my controllers are autowired correctly from Groovy?
Ok, So i have something thats working. Taken from answer 5 How to programmatically create bean definition with injected properties?
public class AppContextExtendingBean implements ApplicationContextAware{
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException{
AutowireCapableBeanFactory beanFactory = applicationContext.getAutowireCapableBeanFactory();
version1(beanFactory);
}
private void version1(AutowireCapableBeanFactory beanFactory){
IUser userController= (UserController) beanFactory.createBean(UserController,AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
beanFactory.initializeBean(userController, "user");
User testuser = userController.getUser(3);
}
}
ApplicationContext ctx = new ClassPathXmlApplicationContext("controller-layer-applicationContext.xml");
AppContextExtendingBean bean = new AppContextExtendingBean();
bean.setApplicationContext(ctx);
We currently have a Spring web application and are doing our configuration using XML files. We are starting Spring the DispatcherServlet which creates an XmlWebApplicationContext and loads it from the default location: spring-servlet.xml.
I am specifying several additional configuration files using the context-param contextConfigLocation. This loads up our entire application from the XML files.
So here's what I want to do. The XML file contains the database connection information and our DAOs for accessing these tables. I want to use one of those DAOs to read a value from the database and load an additional set of beans from the XML file.
So if the database value retrieved is orange, I want to load beans from orange.xml. If it's apple, I want to load apple.xml. I want these beans to be part of the same application context so after they're loaded, I can move forward without noticing the difference.
I'm wondering if I should implement my own sub-class of XmlWebApplicationContext and have DispatcherServlet implement that, but I'm not quite sure how to proceed with that.
Not exactly loading from the different files, but you can try to use Spring Environment and Profile abstractions.
<beans profile="apple">
<bean id="someBean">
...first set of bean parameters...
</bean>
</beans>
<beans profile="orange">
<bean id="someBean">
...second set of bean parameters...
</bean>
</beans>
And in java:
context.getEnvironment().setActiveProfiles("orange");
context.refresh();
You could use a BeanFactoryPostProcessor to load the configuration.
For example, if you have a LocationService that give the config locations as String[]:
public class XmlBeanDefinitionReaderPostProcessor implements BeanFactoryPostProcessor {
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader((BeanDefinitionRegistry) beanFactory);
ResourceLoader resourceLoader = new DefaultResourceLoader();
reader.setResourceLoader(new DefaultResourceLoader());
reader.setEntityResolver(new ResourceEntityResolver(resourceLoader));
reader.setEnvironment(new StandardEnvironment());
LocationService locationService = (LocationService) beanFactory.getBean("locationService");
reader.loadBeanDefinitions(locationService.getLocations());
}
}
Is not exactly the same as the reader is unaware of the already loaded beans and could be aliases or bean names colisions.
Note that your LocationService should not use Autorwire, AOP Transactional Proxies, and something that in general implies the use of BeanPostProcessors.
Other option to reuse the same XmlBeanDefinitionReader is overriding postProcessBeanFactory method in XmlWebApplicationContext:
public class CustomWebApplicationContext extends XmlWebApplicationContext {
private XmlBeanDefinitionReader reader;
#Override
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
this.reader = reader;
super.loadBeanDefinitions(reader);
}
#Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
LocationService locationService = (LocationService) beanFactory.getBean("locationService");
this.reader.loadBeanDefinitions(locationService.getLocations());
super.postProcessBeanFactory(beanFactory);
}
}
We ended up extending XmlWebApplicationContext and overriding the loadBeans method. We load the beans, look up the bean that provides our configuration, then switch profiles and run again with the new profiles.
Thanks for all the help.
I have a spring-based java application with some useful components. As a part of the system I have a groovy script, to process some reports. I would like to call a spring component from groovy script.
When I'm writing in Java, I need to use #Autowired annotation inside the #Component, i.e.
#Component
class Reporter{
#Autowired
SearchService searchService;
void report(){
searchService.search(...);
...
}
}
How can I do the same from groovy?
At first, how I can define #Component for whole script?
The following code:
#Component class Holder{
#Autowired
SearchService searchService;
def run(){
searchService.search("test");
}
}
new Holder().run()
fails with NPE on searchService.
I'm running groovyscripts with GroovyClassloader instatiaded from Java, if it matters.
Thanks a lot in advance!
If you are using #Component, you should create Spring context as:
def ctx = new GenericApplicationContext()
new ClassPathBeanDefinitionScanner(ctx).scan('') // scan root package for components
ctx.refresh()
or in the XML:
<context:component-scan base-package="org.example"/>
Your code should work if the context is created as above. Here is an example from Groovy Codehaus
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component
#Component class CalcImpl3 {
#Autowired private AdderImpl adder
def doAdd(x, y) { adder.add(x, y) }
}
Three possibilities:
If your Groovy code can be pre-compiled and included in the classpath then it will be created and injected as any other bean would be during <context:component-scan>. It sounds like this may not be the case since you are using GroovyClassLoader.
Use Spring Dynamic Language Support and use <lang:groovy> to create your bean instead of using GroovyClassLoader. Then use <lang:property> to inject your properties instead of using #Autowired.
If you still need to use GroovyClassLoader then you can ask the bean to be injected by using AutowiredAnnotationBeanPostProcessor.
For example, if obj is a reference to the object created by GroovyClassLoader:
AutowiredAnnotationBeanPostProcessor aabpp =
(AutowiredAnnotationBeanPostProcessor)applicationContext.
getBean(AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME);
aabpp.processInjection(obj);
There is a fourth possibility too, but I am not sure if it works with GroovyClassLoader, that is to use Load-time Weaving.
I would like to make use of request scoped beans in my app. I use JUnit4 for testing. If I try to create one in a test like this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:spring/TestScopedBeans-context.xml" })
public class TestScopedBeans {
protected final static Logger logger = Logger
.getLogger(TestScopedBeans.class);
#Resource
private Object tObj;
#Test
public void testBean() {
logger.debug(tObj);
}
#Test
public void testBean2() {
logger.debug(tObj);
}
With the following bean definition:
<?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 class="java.lang.Object" id="tObj" scope="request" />
</beans>
And I get:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'gov.nasa.arc.cx.sor.query.TestScopedBeans': Injection of resource fields failed; nested exception is java.lang.IllegalStateException: No Scope registered for scope 'request'
<...SNIP...>
Caused by: java.lang.IllegalStateException: No Scope registered for scope 'request'
So I found this blog that seemed helpful:
http://www.javathinking.com/2009/06/no-scope-registered-for-scope-request_5.html
But I noticed he uses AbstractDependencyInjectionSpringContextTests which seems to be deprecated in Spring 3.0.
I use Spring 2.5 at this time, but thought it shouldn't be too hard to switch this method to use AbstractJUnit4SpringContextTests
as the docs suggest (ok the docs link to the 3.8 version but I'm using 4.4). So I change the
test to extend AbstractJUnit4SpringContextTests... same message. Same problem. And now the prepareTestInstance() method I want
to override is not defined. OK, maybe I'll put those registerScope calls somewhere else... So I read more about TestExecutionListeners and think that would be better since I don't want to have to inherit the spring package structure. So
I changed my Test to:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:spring/TestScopedBeans-context.xml" })
#TestExecutionListeners({})
public class TestScopedBeans {
expecting I would have to create a custom listener but I when I ran it. It works! Great, but why? I don't see where any of the stock listeners
are registering request scope or session scope, and why would they? there's nothing to say I want that yet, this might not be a Test for Spring MVC code...
Solution for Spring 3.2 or newer
Spring starting with version 3.2 provides support for session/request scoped beans for integration testing.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = TestConfig.class)
#WebAppConfiguration
public class SampleTest {
#Autowired WebApplicationContext wac;
#Autowired MockHttpServletRequest request;
#Autowired MockHttpSession session;
#Autowired MySessionBean mySessionBean;
#Autowired MyRequestBean myRequestBean;
#Test
public void requestScope() throws Exception {
assertThat(myRequestBean)
.isSameAs(request.getAttribute("myRequestBean"));
assertThat(myRequestBean)
.isSameAs(wac.getBean("myRequestBean", MyRequestBean.class));
}
#Test
public void sessionScope() throws Exception {
assertThat(mySessionBean)
.isSameAs(session.getAttribute("mySessionBean"));
assertThat(mySessionBean)
.isSameAs(wac.getBean("mySessionBean", MySessionBean.class));
}
}
Read more: Request and Session Scoped Beans
Solution for Spring before 3.2 with listener
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = TestConfig.class)
#TestExecutionListeners({WebContextTestExecutionListener.class,
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class})
public class SampleTest {
...
}
WebContextTestExecutionListener.java
public class WebContextTestExecutionListener extends AbstractTestExecutionListener {
#Override
public void prepareTestInstance(TestContext testContext) {
if (testContext.getApplicationContext() instanceof GenericApplicationContext) {
GenericApplicationContext context = (GenericApplicationContext) testContext.getApplicationContext();
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST,
new SimpleThreadScope());
beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION,
new SimpleThreadScope());
}
}
}
Solution for Spring before 3.2 with custom scopes
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = TestConfig.class, locations = "test-config.xml")
public class SampleTest {
...
}
TestConfig.java
#Configuration
#ComponentScan(...)
public class TestConfig {
#Bean
public CustomScopeConfigurer customScopeConfigurer(){
CustomScopeConfigurer scopeConfigurer = new CustomScopeConfigurer();
HashMap<String, Object> scopes = new HashMap<String, Object>();
scopes.put(WebApplicationContext.SCOPE_REQUEST,
new SimpleThreadScope());
scopes.put(WebApplicationContext.SCOPE_SESSION,
new SimpleThreadScope());
scopeConfigurer.setScopes(scopes);
return scopeConfigurer
}
or with xml configuration
test-config.xml
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="request">
<bean class="org.springframework.context.support.SimpleThreadScope"/>
</entry>
</map>
<map>
<entry key="session">
<bean class="org.springframework.context.support.SimpleThreadScope"/>
</entry>
</map>
</property>
</bean>
Source code
Source code for all presented solutions:
https://github.com/mariuszs/spring-test-web
I've tried several solutions, including #Marius's solution with the "WebContextTestExecutionListener", but it didn't work for me, as this code loaded the application context before creating the request scope.
The answer that helped me in the end is not a new one, but it's good:
http://tarunsapra.wordpress.com/2011/06/28/junit-spring-session-and-request-scope-beans/
I simply added the following snippet to my (test) application context:
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="request">
<bean class="org.springframework.context.support.SimpleThreadScope"/>
</entry>
</map>
</property>
</bean>
Good luck!
A solution, tested with Spring 4, for when you require request-scoped beans but aren't making any requests via MockMVC, etc.
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(/* ... */)
public class Tests {
#Autowired
private GenericApplicationContext context;
#Before
public void defineRequestScope() {
context.getBeanFactory().registerScope(
WebApplicationContext.SCOPE_REQUEST, new RequestScope());
RequestContextHolder.setRequestAttributes(
new ServletRequestAttributes(new MockHttpServletRequest()));
}
// ...
The test passes because it isn't doing anything :)
When you omit the #TestExecutionListeners annotation, Spring registers 3 default listeners, including one called DependencyInjectionTestExecutionListener. This is the listener responsible for scanning your test class looking for things to inject, including #Resource annotations. This listener tried to inject tObj, and fails, because of the undefined scope.
When you declare #TestExecutionListeners({}), you suppress the registration of the DependencyInjectionTestExecutionListener, and so the test never gets tObj injected at all, and because your test is not checking for the existence of tObj, it passes.
Modify your test so that it does this, and it will fail:
#Test
public void testBean() {
assertNotNull("tObj is null", tObj);
}
So with your empty #TestExecutionListeners, the test passes because nothing happens.
Now, on to your original problem. If you want to try registering the request scope with your test context, then have a look at the source code for WebApplicationContextUtils.registerWebApplicationScopes(), you'll find the line:
beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());
You could try that, and see how you go, but there might be odd side-effects, because you're not really meant to do this in a test.
Instead, I would recommend rephrasing your test so that you don't need request scoped beans. This shouldn't be difficult, the lifecycle of the #Test shouldn't be any longer than the lifecycle of a request-scoped bean, if you write self-contained tests. Remember, there's no need to test the scoping mechanism, it's part of Spring and you can assume it works.
This is still an open issue:
https://jira.springsource.org/browse/SPR-4588
I was able to get this to work (mostly) by defining a custom context loader as outlined in
http://forum.springsource.org/showthread.php?p=286280
Test Request-Scoped Beans with Spring explains very well how to register and create a custom scope with Spring.
In a nutshell, as Ido Cohn explained, it's enough to add the following to the text context configuration:
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="request">
<bean class="org.springframework.context.support.SimpleThreadScope"/>
</entry>
</map>
</property>
</bean>
Instead of using the predefined SimpleThreadScope, based on ThreadLocal, it's also easy to implement a Custom one, as explained in the article.
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;
public class CustomScope implements Scope {
private final Map<String , Object> beanMap = new HashMap<String , Object>();
public Object get(String name, ObjectFactory<?> factory) {
Object bean = beanMap.get(name);
if (null == bean) {
bean = factory.getObject();
beanMap.put(name, bean);
}
return bean;
}
public String getConversationId() {
// not needed
return null;
}
public void registerDestructionCallback(String arg0, Runnable arg1) {
// not needed
}
public Object remove(String obj) {
return beanMap.remove(obj);
}
public Object resolveContextualObject(String arg0) {
// not needed
return null;
}
}
MariuszS' solution works, except I couldn't get the transaction committed properly.
It seems the newly released 3.2 has finally made testing request/session scoped beans first class citizens. Here's a couple of blogs for more details.
Rossen Stoyanchev's Spring Framework 3.2 RC1: Spring MVC Test Framework
Sam Brannen's Spring Framework 3.2 RC1: New Testing Features
NOT reading the docs sometimes drives one crazy. Almost.
If you are using shorter-lived beans (request scope for example), you most likely also need to change your lazy init default! Otherwise the WebAppContext will fail to load and tell you something about missing request scope, which is of course missing, because the context is still loading!
http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html#beans-factory-lazy-init
The Spring guys should definitely put that hint into their exception message...
If you don't want to change the default, there is also the annotation way: put "#Lazy(true)" after #Component etc. to make singletons initialize lazy and avoid instantiating request-scoped beans too early.