No matching bean when testing but works perfectly on server - java

I'm working on a spring-mvc project built by someone else. Everything works fine when running with Tomcat on localhost using Eclipse. I have also committed some code and they have been deployed by the supervisor successfully.
However, when I run a JUnit test which is basically as follows:
package com.my.package.test;
...
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = "classpath*:*/applicationContext.xml")
public class DataSynchronizationTest {
#Autowired
SomeMapper someMapper;
//some tests
}
I'm suddenly getting the error:
... org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.company.project.dao.SomeMapper] found for dependency: ...
This seems weird to me because that's exactly how someMapper is injected in the web application. For example, the following works just fine:
package com.my.package.controller;
...
#Controller
#RequestMapping("/foo")
#Scope("session")
public class FooController extends BaseController {
#Autowired
SomeMapper someMapper;
//...
}
I think I'm loading ApplicationContext correctly in this JUnit test because if I remove that #ContextConfiguration line or change it to #ContextConfiguration(locations = "/applicationContext.xml") then I would get the following error:
java.lang.IllegalStateException: Failed to load ApplicationContext
So if I'm using the same ApplicationContext (there is only one. I didn't create another one for testing), why does the injection works fine on server, but fails in JUnit test? Any help is appreciated.
Edit:
As M. Deinum said in the comment, I do have a ContextLoaderListener and a DispatcherServlet, both of which are defined in web.xml. Here is the relevant part of web.xml:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
However, someMapper lives in the applicationContext.xml (which is loaded by ContextLoaderListener) and apparently has nothing to do with the DispatcherServlet part. Here is the part of applicationContext.xml that is responsible for loading someMapper:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mapperLocations" value="classpath:com/company/project/dao/*.xml" />
<property name="configLocation" value="classpath:MyBatis-Configuration.xml"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.company.project.dao" />
</bean>
SomeMapper.java and SomeMapper.xml are located in classpath:com/company/project/dao/, of course.

Related

Spring Scheduling: #Scheduled annotation on a method inside a class annotated with #Controller runs twice

Consider the below code snippet:
#Controller
public class RestController {
#Scheduled(cron = "0 0 */* * * ?") // run every hour
public void runMeHourly() {
LOGGER.debug("RestController#runMeHourly triggered to run at: " + System.currentTimeMillis());
// Do your hourly work here
}
}
When I deploy this controller in a J2EE web server I see that the method RestController#runMeHourly() in triggered twice every hour.
I found a reference to something like this here on spring docs scheduling.
It says:
Make sure that you are not initializing multiple instances of the same #Scheduled annotation class at runtime, unless you do want to schedule callbacks to each such instance. Related to this, make sure that you do not use #Configurable on bean classes which are annotated with #Scheduled and registered as regular Spring beans with the container: You would get double initialization otherwise, once through the container and once through the #Configurable aspect, with the consequence of each #Scheduled method being invoked twice.
Is this related? Does this mean I need to Schedule the method runMeHourly() from outside the RestController?
[Edit 1: Looks like the #Configurable is something else and not contributing to the problem, and I have not used it anywhere. So there must be some other reason that is causing this behaviour]
[Edit 2:
My web.xml:
<web-app>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
</context-param>
<listener>
<listener-class>com.company.module.ModuleContextListener</listener-class>
</listener>
</web.xml>
mvc-dispatcher-servlet.xml
<beans>
<mvc:annotation-driven />
<task:annotation-driven />
<context:component-scan base-package="com.company" />
<import resource="module/module-servlet.xml"/>
</beans>
module/module-servlet.xml
<beans>
<context:component-scan base-package="com.company.module"/>
</beans>
]
The com.company.module.ModuleContextListener is forcing the DispatcherServlet to look for a root application context, and since the root application context is same as mvc-dispatcher-servlet.xml its being loaded twice. Once as root context and again under DispatcherServlet with the name mvc-dispatcher.
Renaming the root context xml mvc-dispatcher-servlet.xml to applicationContext.xml and adding an empty mvc-dispatcher-servlet.xml solves the problem.
Thanks to #6ton for pointing this out.

how i can tell glassfish about my spring dependancy injection?

I am new here, I am working on a project using hibernate and spring dependency injection and SOAP web service.
My problem is when I run my project in the console using this class:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-beans.xml");
IServicesPharmacie pharmacieService = (IServicesPharmacie) context.getBean("service");
context.close();
Endpoint.publish("http://localhost:3597/Pharmacies", pharmacieService);
System.out.println("The service has been published with success!");
my project work fine, because with these 3 lines:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-beans.xml");
IServicesPharmacie pharmacieService = (IServicesPharmacie) context.getBean("service");
context.close();
I can tell about my spring dependancy injection.
BUT i don't know how to run my project on a glassfish server, and tell him about my spring dependancy injection, I guess that I most have a web.xml!!!!
My spring-beans.xml is like that :
<bean class="dao.PharmImpl" id="dao"></bean>
<bean class="metier.PharMetier" id="metier">
<property name="phardao" ref="dao"></property>
</bean>
<bean class="services.ServicesPharmacie" id="service">
<property name="servmetier" ref="metier" />
</bean>
</beans>
You need to configure a ContextLoaderListener to bootstrap spring in your application. like below:
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
Perhaps if you are using springMVC its done as below:
<servlet>
<servlet-name>springServlet</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
Please note URL-pattern is based on your requirement.

Spring afterPropertiesSet invoke before Servlet init?

I want to do some database search after tomcat startup.
So I just implements InitializingBean and implement method afterPropertiesSet and put database operating in afterPropertiesSet.
And, my project is using proxool.
Then I startup tomcat to test afterPropertiesSet method. I got this error
org.logicalcobwebs.proxool.ProxoolException: Attempt to refer to a unregistered pool by its alias
I thought its some thing wrong with the order of startup of the components in web.xml
<servlet>
<servlet-name>ServletConfigurator</servlet-name>
<servlet-class>org.logicalcobwebs.proxool.configuration.ServletConfigurator</servlet-class>
<init-param>
<param-name>propertyFile</param-name>
<param-value>WEB-INF/classes/jdbc.properties</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>ProxoolAdmin</servlet-name>
<servlet-class>org.logicalcobwebs.proxool.admin.servlet.AdminServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ProxoolAdmin</servlet-name>
<url-pattern>/proxool/admin</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:config/application-context-*.xml</param-value>
</context-param>
Then I set one breakpoint at the first line of afterPropertiesSet method, the second breakpoint at the init method of org.logicalcobwebs.proxool.configuration.ServletConfigurator.
To avoid the error before, I just type a single print operat in afterPropertiesSet.
Then I startup tomcat to check the order of afterPropertiesSet and ServletConfigurator.
afterPropertiesSet method is invoked before ServletConfigurator init.
I have been figure out why I got Attempt to refer to a unregistered pool by its alias error.
But, How to let afterPropertiesSet invoke after ServletConfigurator init?
EDIT
And there is class GoodsRecommendService
#Service
public class GoodsRecommendServiceImpl implements InitializingBean {
#Override
public void afterPropertiesSet() throws Exception {
System.out.println("There is invoked before servlet init!!");
}
}
The issue is being caused by the fact that ServletContextListeners are invoked before all Servlets of the context are created. As the API for ServletContextListener states:
Receives notification that the web application initialization process is starting.
All ServletContextListeners are notified of context initialization before any filters or servlets in the web application are initialized.
So in your configuration:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:config/application-context-*.xml</param-value>
</context-param>
means that your Spring ApplicationContext is created before any of the Servlets. This is why you are getting your error.
To fix it you need to ensure that whatever you are trying to do in your bean, you do it once the Proxool servlet is properly initialised.
I think the easiest way to do this is to switch your Spring ApplicationContext to be loaded by DispatcherServlet and ensure that the load-on-startup value for DispatcherServlet is greater than that of the Proxool servlet.
For more information on DispatcherServlet, see here.
An alternative approach might be to make sure Spring application context will configure Proxool, as in the following example:
<bean id="proxoolProperties" class=" org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location" value="classpath:proxool.properties"/>
</bean>
<bean id="proxoolConfiguration" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass" value="org.logicalcobwebs.proxool.configuration.PropertyConfigurator" />
<property name="targetMethod" value="configure" />
<property name="arguments" ref="proxoolProperties" />
</bean>

#Autowired doesn't work in Spring and Vaadin integration

I'm trying to integrate Spring with Vaadin, but I can't use the #Autowired annotation in my Vaadin classes.
Firstly, I created the followed maven structure
This is my web.xml
<web-app>
<display-name>Vaadin Web Application</display-name>
<context-param>
<description>Vaadin production mode</description>
<param-name>productionMode</param-name>
<param-value>false</param-value>
</context-param>
<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>/WEB-INF/application-context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class> org.springframework.web.context.request.RequestContextListener </listener-class>
</listener>
<servlet>
<servlet-name>Vaadin Application Servlet</servlet-name>
<servlet-class>com.mycompany.config.AutowiringApplicationServlet</servlet-class>
<init-param>
<description>Vaadin UI to display</description>
<param-name>UI</param-name>
<param-value>com.mycompany.ui.MyUI</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Vaadin Application Servlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
This is my application-context.xml
<bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.postgresql.Driver" />
<property name="url" value="jdbc:postgresql://localhost/vaadin" />
<property name="username" value="postgres" />
<property name="password" value="tobbis" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="datasource"/>
<property name="persistenceUnitName" value="myUnit"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<jpa:repositories base-package="com.mycompany.repository"></jpa:repositories>
<context:annotation-config/>
<context:component-scan base-package="com.mycompany" />
Now I created my UserService that is within com.mycompany.services package
#Service
public class UserService {
public void saveUser(User user){
System.out.println("Test to Save");
}
}
And finally, I have my Panel where I want to inject the service
public class UserPanel extends VerticalLayout {
#Autowired
UserService service;
public UserPanel() {
// TODO Auto-generated constructor stub
Injector.inject(this);
service.saveUser();
}
}
but the result is always the same
Error creating bean with name 'com.mycompany.ui.UserPanel': Injection of autowired dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException:
Could not autowire field: com.mycompany.services.UserService com.mycompany.ui.UserPanel.service;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:
No matching bean of type [com.aiem.services.UserService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency.
Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
Try to declare your UserService at applicationContext.xml
<bean name="userService" class="com.mycompany.services.UserService"></bean>
As far as I know,
Injector.inject(this);
is not something from Spring, you may be mixing it with another framework.
Instead, I would make UserPanel a prototype-scoped Spring component (meaning it can be instantiated and autowired by Spring, but you remain responsible for it's lifecycle).
#Component
#Scope(SCOPE_PROTOTYPE)
public class UserPanel extends VerticalLayout {
Note that a new instance will be created anytime UserPanel is retrieved from the context (e.g. autowired in another object). It could be best to control the creation of instances yourself by explicitly invoking
context.getBean(UserPanel.class)
at the right time.
AnnotationConfigWebApplicationContext is not meant to be used with XML config. It is supposed to be used with the #Configuration annotated classes.
Since you're using an xml file for Spring config, then you should instead remove these lines from web.xml:
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>
And then by default Spring will use the XmlWebApplicationContext and pick up your xml file.
I have tried the same scenario than you. At the end, the solution is at the Vaadin documentation.
Seems that the problem is that we are using Vaadin context and not Spring context, and therefore we need to do the trick showed in the documentation (SpringHelper) to obtain any bean. Outside of the Spring context, the autowiring is not goint to work.
There is an addon for enabling autowiring via annotations: http://vaadin.xpoft.ru/.
Here is the link to the Vaadin site: http://vaadin.com/addon/springvaadinintegration. Hope it helps.

Better way to access beanFactory in Spring3 Web App

I am trying to find a better way to access beanFactory in Spring3 Web App. Right now I setup a config.xml file with all my services that my system is going to use and in the controller I ad a line of code like:
private static XmlBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("config.xml"));
in each controller.. Does anyone know of any better way to do this?
If you're using Spring MVC, presumably you've defined a servlet in web.xml to handle the requests, like:
<servlet>
<description></description>
<display-name>dispatcher</display-name>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
In which case you should have a Spring config file named something like dispatcher-servlet.xml in your web-inf directory. Put your bean definitions in there and they will get defined and be available when the servlet starts up.
EDIT:
Importing one bean configuation file into another, from section 3.2.2.1 of the Spring reference:
<beans>
<import resource="services.xml"/>
<import resource="resources/messageSource.xml"/>
<import resource="/resources/themeSource.xml"/>
<bean id="bean1" class="..."/>
<bean id="bean2" class="..."/>
</beans>
Autowiring bean example in controller:
#Controller
public class MyController {
#Autowired
private MyBeanClass myBeanName;
...
}

Categories