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);
Related
I'm trying to get a better understanding of the #Autowired annotations component scanning, but all the examples I found so far use context.getBean(..) at some point to get at least one Bean to start with.
I also read that doing that is considered bad practice , but I can't seem to find any information on how to do it without context.getBean(..)
Could somebody please enlighten me with an example and information on how to do this ?
Define your bean in xml and use
<context:component-scan base-package="com" />
<mvc:annotation-driven />
Bean def
<bean id="processEngine" class="com.processEngine">
<property name="processEngineConfiguration" ref="processEngineConfiguration" />
</bean>
now you can get bean as following
#Autowired
private ProcessEngine processEngine;
how it works
spring scans the bean's recipes either from xml or java configuration. then spring creates a beanDefinitions which are 'loaded' into BeanFactory. BeanFactory triggers a set of BeanPostProcessors (BPP) which are scanning classes for particular annotations like Autowired/Resource/PostProcessor and etc. and do appropriate actions. in case when your class contains #Autowired annotation, AutowiredAnnotationBeanPostProcessor would auto wire required field (dependencies), and when creation of an object is done and all BPP worked out, object is ready to be used by the app, from this point your code can get 'ready' objects from container.
there are some cases when you would need to access this beans from the code which is out of spring's control and not managed by container. in order to do so, you would need to get the ApplicationContext (container) and call #getBean specifying either name or type. using applicationContext directly is not a good practice because there are some problems that you can come to, f.ex. id of a bean might be changed and if you refer to bean by id then NPE would be thrown.
configuration
there are several approaches to configure spring to scan the classes for finding bean recipes. one would be defining component-scan, in this case classes which are located in the path that you've set and having any of valid spring annotations like #Component, #Service, #Repository, #Controller (for web container) would be considered. another way would be specifying each bean separately using <bean> or #Bean.
examples.
if you want to create a web app then you should see DispatcherServlet with ContextLoaderListener classes. this classes would boot your app and load everything according to configuration. f.ex. here,
but if you want to create a desktop app, then you would end up with something like this
From time to time (usually when not using Spring Boot), I use something along the lines of the following code:
public static <T> T autowire(ApplicationContext ctx, T bean) {
ctx.getAutowireCapableBeanFactory().autowireBean(bean);
return bean;
}
In my main, I create an instance of the main application class that contains a few #Autowired annotations for the main services / entry points to my Spring application.
I use Spring 3 to make a simple configuration.
I have an XML file called PropertyBeans.xml like that :
<bean id="propertyBean" class="com.myapp.PropertyBean">
<property name="rootDirLogPath" value="C:\Users\dede" />
</bean>
I have the bean which match this XML and then I want to use this bean with the value injected. Actually I have :
ApplicationContext context = new ClassPathXmlApplicationContext("AppPropertyBeans.xml");
PropertyBean obj = (PropertyBean) context.getBean("propertyBean");
String rootDirLogPath = obj.getRootDirLogPath();
This works great but I want to know if there's a way to avoid the instantiation of ApplicationContext at each time I want to use a bean. I've heard about BeanFactory is that a good idea? Which are the others solutions?
In other words: Am I supposed to called this Application context instanciation in every Controller in spring MVC?
If you want to use spring beans in controllers, add line to applicationContext.xml:
<context:spring-configured/>
<task:annotation-driven/>
<context:component-scan base-package="by" />
Then write your controller following way:
#Controller
public class IndexController {
#Autowired
private UserService userService;
#Autowired
private GroupService groupService;
// methods with #RequestMapping annotation
}
This is trivial thing, so If you have questions it is strongly recommended to read "Spring in action book", chapter 7: Building web applications
The whole idea of the ApplicationContext is that there is one (hence the name, context of the application).
So if you're creating a new one every time, you're doing it wrong.
If you use dependency injection properly, the object containing that code will already be instantiated by the injection container (Spring) and the propertyBean will have been injected.
Use autowiring or implements the InitializingBean interface.
You can simply add the context as member in your class like:
private ApplicationContext context;
and instanciate it in the constructor or an init() method.
I am new to Spring framework. Maybe this is more of a Java EE bean design question than related to Spring framework. Anyway, I just shoot it and see how clear I can make myself.
So I have a service. The service takes a connection string as constructor parameter. Then you can use the service to upload files to the location indicated by the connection string.
So you will start with something like:
public class MyService{
public MyService(String connectionStr){ ... }
}
When you need such a service, you call:
MyService service = new MyService("xxx");
...
That's what I used to do. Nothing fancy. Now if I do it in Java under Spring, I somehow want the service to be a bean. I need to do this:
#Component
public class MyService{
#Autowired
public MyService(#Value(...some connection string...) String connectionStr) {...}
}
But I get confused how you can inject dependency in compile time? I never know what connection string I will pass to create the service. When I read Spring tutorials, most of them have parameters coded in XML config file. Can I design a Spring bean like the one above but require the parameters to be passed in runtime?
Thanks.
You can design a method like this:
void upload(String location,XXX other parameters);
I didnt really get your question but will try to answer.
Check here or google to check if you really want to go for spring.
Coming to your query, For your service you would have to define some thing like this in your spring context.
<bean id="myService" class="com.blah.MyService">
<constructor-arg>
<value>http://HOST/test/</value>
</constructor-arg>
</bean>
Your service class will be,
public class MyService{
public MyService(String connectionString) {...}
}
This is how you will call your service in your application
ApplicationContext context = new ClassPathXmlApplicationContext(
new String[] { "context.xml" });
MyService service = (MyService) context
.getBean("myService");
The above can be implemented using annotations also. Check here for more details
I want to test my spring mvc controller.
The controller has a service:
#Autowired
UserService userService
And my user service depends on (autowired) my UserDao and some other services like mongoDb etc.
Now I want the business logic to be tested in my UserService, but ofcourse I want to mock the responses from my UserDao and Mongodb etc.
How do I setup my unit test correctly?
Can I re-use the spring container's xml file that has all my beans etc. or do I create a new one? (I'm assuming I have to get the spring container involved here)
Looking for some guidance on this, any tutorials would be greatly appreciated.
Update
What I find strange is that for my spring controller (that doesn't implement from Controller) I was able to access my private varialbe to manually set my service, i.e:
#Controller
public class UserController {
#Autowired
UserService userService;
}
And in my unit test I could do:
UserController controller = new UserController();
controller.userService = ....
But for my UserService, which has UserDao autowired, I can't access the userDao property:
UserService userService = new UserServiceImpl();
userService.userDao = .... // not available
It makes sense since it is private, but how is it working for my controller?
Spring framework has very interesting features for testing. You can take a look at Spring reference guide. It can provide DI even in your JUnit test class.
#RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from "/applicationContext.xml" and "/applicationContext-test.xml"
// in the root of the classpath
#ContextConfiguration(locations={"/applicationContext.xml", "/applicationContext-test.xml"})
public class MyTest {
// class body...
}
Briefly, you can use your own applicationContext.xml or even define a new one just for testing. I personally use a different one since I define another dataSource dedicated for testing purposes.
What I find strange is that for my spring controller (that doesn't implement from Controller) I was able to access my private varialbe to manually set my service, i.e:
This is easy: the varible in not private.
It has the default visibility ("package private"). This mean you can access them from all classes of the same package.
So if you have a common structure, then the controller and the controller test case are in the same package. Therefore you can modify the ("package private") controller fields. But the controller test case and the service are not in the same packaged, so you can not access the ("package private") service fields.
Can I re-use the spring container's xml file that has all my beans
etc. or do I create a new one? (I'm assuming I have to get the spring
container involved here)
I would advice against creating new xml file. You would end up duplicating lot of stuff and its going to be hard to maintain. There would be proliferation of config files. You put the config required for tests in a different xml and that should not even be deployed to your production box. So far as using the config for your beans, you can employ the mechanism as suggested by #Trein.
For testing spring contrller in general, you may also find this SO Thread useful.
Hope that helps.
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.