Spring #EventListener annotation doesn't work with #Service annotation - spring-mvc

Here are two objects I want to receive ContextRefreshedEvent
#Component
public class InitDB {
#EventListener
public void handleContextRefresh(ContextRefreshedEvent e) {
//
}
}
InitDB works as expected, but in this case not:
#Service
public class MyService implements IMyService{
#Autowired
private MyDao _dao; // Autowired WORKs
#EventListener
public void handleContextRefresh(ContextRefreshedEvent e) {
// DOESN'T WORK
}
[...]
}
Any Idea what I'm doing wrong?
Here are my maven properties
<properties>
<java-version>1.7</java-version>
<org.springframework-version>4.2.2.RELEASE</org.springframework-version>
<spring-security-web-version>3.2.5.RELEASE</spring-security-web-version>
<org.aspectj-version>1.7.2</org.aspectj-version>
<org.slf4j-version>1.5.10</org.slf4j-version>
<hibernate-version>4.3.6.Final</hibernate-version>
<json-jackson-version>2.4.1</json-jackson-version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<skipTests>true</skipTests>
</properties>

I had the same problem and for me, it proved my listener bean wasn't loaded in the dependencies by Spring.
If you use Spring Boot Actuator, you can check the loaded beans at https://localhost:8443/beans.
The bean wasn't detected by Spring because I had a namespace typo. My main namespace was com.foo (with packages like com.foo.security and com.foo.controllers), and when I added a new package logging, I introduced a typo in the namespace: com.ffoo.logging.
Because of this, Spring could not find the new Components/Services I was adding.
For this particular question, it doesn't matter if it's annotated with #Service, because #Service is a sub-class of #Component (see post)

Related

How do I inject an EJB in Spring MVC using annotations?

My dispatcher-servlet.xml has basically:
<context:component-scan base package="package.ejb" />
<mvc:annotation-driven />
In the #Controller class I have:
#Controller
public class ApplicationController {
#EJB(lookup="java:global/MyEarName/MyWebModuleName/BeanImplementation!package.ejb.morepackages.BeanImplementation")
private MyBeanInterface myBean;
This didn't work, it looks like Spring doesn't see the #EJB annotation and it gives an error at deploy time saying it doesn't find any Autowire candidate. So I added the following code:
#Autowired
#Qualifier("BeanImplementation")
public void setMyBean(MyBeanInterface myBean) {
this.myBean = myBean;
}
And on my bean implementation:
#Component("BeanImplementation")
#Stateless(mappedName = "BeanImplementation", name = "BeanImplementation")
#LocalBean
public class BeanImplementation implements MyBeanInterface {
It worked, but I need to use the lookup string of the EJB and I can't since Spring doesn't see #EJB. I was forced to revert to a non-Spring application to use #EJB(lookup="...").
So, to clarify the question: how do I inject an EJB in Spring MVC using annotations and using the EJB lookup string? Thanks.

spring boot test unable to inject TestRestTemplate and MockMvc

I am using spring boot 1.4.0.RELEASE. I am writing tests for my controller class. I get the following exception.
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.concur.cognos.authentication.service.ServiceControllerITTest': Unsatisfied dependency expressed through field 'restTemplate': No qualifying bean of type [org.springframework.boot.test.web.client.TestRestTemplate] found for dependency [org.springframework.boot.test.web.client.TestRestTemplate]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.boot.test.web.client.TestRestTemplate] found for dependency [org.springframework.boot.test.web.client.TestRestTemplate]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
Here is my test class
public class ServiceControllerITTest extends ApplicationTests {
#Autowired
private TestRestTemplate restTemplate;
#Autowired
private MockMvc mvc;
#Test
public void exampleTest() throws Exception {
// test
}
}
ApplicationTests.java
#RunWith(SpringRunner.class)
#SpringBootTest
#WebAppConfiguration
//#DirtiesContext
public class ApplicationTests {
#Autowired
Environment env;
#Test
public void contextLoads() {
}
}
TestRestTemplate is only auto-configured when #SpringBootTest has been configured with a webEnvironment that means it starts the web container and listens for HTTP requests. For example:
#SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
If you read the java doc of SpringBootTest annotation, it says that annotation provides below features (not listing all of them here, but only what are relevant to the question.)
Provides support for different webEnvironment modes, including the ability to start a fully running web server listening on a defined or random port.
Registers a TestRestTemplate and/or WebTestClient bean for use in web tests that are using a fully running web server listening on a defined or random port.
So #SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT) provides the ability to autowire TestRestTemplate because it starts a fully running web server [as mentioned in #AndyWilkinson' answer as well].
But if you want to autowire MockMvc as well in same TestClass then use
#AutoConfigureMockMvc annotation over TestClass.
This is how a Test class may look like:
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
#AutoConfigureMockMvc
public class SBTest {
#Autowired
private TestRestTemplate restTemplate;
#Autowired
private MockMvc mvc;
// tests
}
To work with that, don't use a deprecated TestRestTemplate.
Deprecated:
import org.springframework.boot.test.TestRestTemplate;
Correct:
import org.springframework.boot.test.web.client.TestRestTemplate;
Then you can use the #Autowired annotation in your class:
#Autowired
private TestRestTemplate restTemplate;
And don't use:
#Autowired
private MockMvc mvc;
Both together doesn't work.
According to Spring boot documentation :
You can also auto-configure MockMvc in a non-#WebMvcTest (e.g. SpringBootTest) by annotating it with #AutoConfigureMockMvc.

Spring boot No WebApplicationContext found

I have a simple spring boot app and I'm trying to get it up and running. The config consists of an app context ( applicationContext.xml) XML with a bunch of beans in it. I have a Spring application class:
#SpringBootApplication
#Configuration
#ImportResource("classpath:applicationContext.xml")
public class WebCheckApplication {
private static final Logger logger = Logger.getLogger(WebCheckApplication.class);
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(WebCheckApplication.class, args);
if (logger.isDebugEnabled()) {
logger.debug("Let's inspect the beans provided by Spring Boot:");
String[] beanNames = ctx.getBeanDefinitionNames();
Arrays.sort(beanNames);
for (String beanName : beanNames) {
logger.debug(beanName);
}
}
}
}
And I have a #WebListener class that grabs a few beans from the WebContext from within the ServletContext:
#WebListener
public class SystemPropertiesContextInitializer extends SysPropsAlertsFetcher implements ServletContextListener {
private static final Logger logger = Logger.getLogger(SystemPropertiesContextInitializer.class);
#Override
public void contextDestroyed(ServletContextEvent sce) {
//remove the SystemProperties and alert types map object from context
sce.getServletContext().removeAttribute(BaseAuthenticatedController.SYSPROPS_KEY);
sce.getServletContext().removeAttribute(BaseAuthenticatedController.ALERT_TYPES_MAP_KEY);
}
#Override
public void contextInitialized(ServletContextEvent sce) {
SysPropsDataAccess = (SystemPropertiesDataAccess) WebApplicationContextUtils.getRequiredWebApplicationContext(sce.getServletContext()).getBean("SystemPropertiesDataAccess");
AlertsDataAccess = (AlertDataAccess) WebApplicationContextUtils.getRequiredWebApplicationContext(sce.getServletContext()).getBean("AlertsDataAccess");
fetchObjects(sce.getServletContext());
}
}
When I attempt to start the app, I get the following error:
SEVERE: Exception sending context initialized event to listener instance of class web.SystemPropertiesContextInitializer
java.lang.IllegalStateException: No WebApplicationContext found: no ContextLoaderListener registered?
at org.springframework.web.context.support.WebApplicationContextUtils.getRequiredWebApplicationContext(WebApplicationContextUtils.java:83)
at .web.SystemPropertiesContextInitializer.contextInitialized(SystemPropertiesContextInitializer.java:31)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4994)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5492)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
and it occurs at this line:
SysPropsDataAccess = (SystemPropertiesDataAccess) WebApplicationContextUtils.getRequiredWebApplicationContext(sce.getServletContext()).getBean("SystemPropertiesDataAccess");
It looks like Spring isn't creating a WebApplicationContext.
Greater than or equal 1.3.0.RC1 use #ServletComponentScan
#ServletComponentScan // <-- This scans for EJB #WebFilter, #WebListener and #WebServlet
#SpringBootApplication
#ImportResource("classpath:applicationContext.xml")
public class WebCheckApplication {
Less than or equal 1.2.x use #Component to scan for listener
#Component // <-- This allows the component to be found by #ComponentScan inside of #SpringBootApplication
#WebListener
public class MojoSystemPropertiesContextInitializer extends MojoSysPropsAlertsFetcher implements ServletContextListener {
War Deploy extend SpringBootServletInitializer
public class WebCheckApplication extends SpringBootServletInitializer {
In 1.3.0.RC1 #ServletComponentScan was added so simply annotating your main application config should allow these to be picked up. Otherwise adding #Component to your ServletContextListener should work
This link is a discussion on how they currently handle #WebFilter how they decided to handle #WebFilter and they also discuss SpringBootServletInitializer and how this would pick process each item twice if both were to be used. Also links to the commits that implement the new feature.
https://github.com/spring-projects/spring-boot/issues/2290
If you intend to deploy your application as a war file you may also have your main configuration extend SpringBootServletInitializer
http://docs.spring.io/spring-boot/docs/current/reference/html/howto-traditional-deployment.html
All that was needed was to make the Application class extend SpringBootServletInitializer

Autowiring inside contextInitialized method of Context Listener

I am trying to autowiring my bean inside contextInitialized() method of my custom Context Listener class, but it is not working.
public class CustomContextListener extends ContextLoaderListener {
#Autowired
private MyBeanClass bean;
#Override
public void contextInitialized(javax.servlet.ServletContextEvent event) {
super.contextInitialized(event);
//call to my method.
bean.mymethod();
}
But here it is not getting autowired, i am getting null object for MyBeanClass reference.
How to autowire a class at the time of tomcat startup.
Please provide me alternate places where i can execute some code using autowiring at the time of server startup (here tomcat).
I would suggest to use the WebApplicationContext method to find the bean and then invoke.
WebApplicationContext servletContext = WebApplicationContextUtils.getWebApplicationContext(event.getServletContext());
bean = (MyBeanClass) servletContext.getBean("myBeanClass");
bean.yourMethod();
More systematic to use... :)

WELD-001408 Unsatisfied dependencies when injecting EJBs that implement interfaces

Here is the situation.
I've got the following interfaces:
public interface Parent { }
public interface ChildOne extends Parent { }
public interface ChildTwo extends Parent { }
and 2 EJBs:
#Stateless
public class FirstBean implements ChildOne { }
#Stateless
public class SecondBean implements ChildTwo { }
And also this CDI Bean:
#Named
#SessionScoped
public class TestController implements Serializable {
#Inject
private FirstBean firstBean;
#Inject
private SecondBean secondBean;
}
While trying to deploy this on Glassfish 3.1 I get the following exception:
Exception while loading the app : WELD-001408 Unsatisfied dependencies for type [FirstBean]
with qualifiers [#Default] at injection point [[field] #Inject private com.test.controllers.TestController.firstBean]
org.jboss.weld.exceptions.DeploymentException: WELD-001408 Unsatisfied dependencies for type [FirstBean]
with qualifiers [#Default] at injection point [[field] #Inject private com.test.controllers.TestController.firstBean]
at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:305)
When both EJBs implement the Parent interface, the exception is the same.
Also, I tried adding qualifiers, but that didn't change anything.
I just played around with your construct, read a bit of the weld docu and found out the following.
You are using EJBs that implement an interface, so the no-interface view is not possible anymore (obviously), but you are trying to directly access the implementation. As soon as you declare it as an EJB you have to keep in mind the conventions. So, if you define an interface you have to use it to get access to the EJB. Changing it to the following, should work out:
#Inject
private ChildOne firstBean;
Accessing the implementation even though an interface is defined is just possible for plain CDI Managed Beans (classes without the #Stateless/#Stateful annotations). So get rid of your annotation and it will work out.
Just for your information, if you are using Glassfish. If you stick to your EJBs and try to access the parent interfaces method you will run into this bug / exception.
Better late than never:
Annotating the SLSB aditionally with #LocalBean works for me with JBoss AS 7.1.1. I don't like the idea of creating the interface for no added value.
Using your example:
#Stateless
#LocalBean
public class FirstBean implements ChildOne { }
#Stateless
#LocalBean
public class SecondBean implements ChildTwo { }
Have you tried using #EJB annotation rather then the CDI #inject annotation?
E.g.
#Named
#SessionScoped
public class TestController implements Serializable {
#EJB
private FirstBean firstBean;
#EJB
private SecondBean secondBean;
}

Resources