WebApplicationContext appears to ignore Import annotation - spring

I am having a problem where the Spring WebApplicationContext appears to be ignoring the #Import annotation on a #Configuration-annotated config class in my web app. It is not a Spring MVC web app.
The problem occurs during processing of the contextInitialized event of a custom ServletContextListener which used to be able to successfully retrieve this bean when I was using XML configuration, but is now not finding this bean now that I have (apparently incorrectly) converted to the use of #Configuration-annotated classes.
The symptoms I see are:
During app startup, I see this output from the Spring framework:
INFO: No annotated classes found for specified class/package
[org.imaginary.spring.config.Instrumented]
Later, when my contextInitialized() method is invoked and I call getBean(), I get a NoSuchBeanDefinition exception
My config classes are factored in such a way that I have, for example, two high-level config classes, one for a "Production" configuration, and another for an "Instrumented" configuration. These top-level config classes are themselves completely empty, but they make use the #Import annotation to (I'm hoping) bring in the relevant bean definitions for that kind of configuration.
For example, here is the Instrumented configuration class:
package org.imaginary.spring.config;
import org.imaginary.spring.config.instrumentation.InstrumentationDependencies;
import org.imaginary.spring.config.servlets.ServletDependencies;
#Configuration
#Import( {InstrumentationDependencies.class, ServletDependencies.class } )
public class Instrumented
{
}
...for the purposes of this example, here is the InstrumentationDependencies config class, defined in a different package:
package org.imaginary.spring.config.instrumentation;
#Configuration
public class InstrumentationDependencies
{
#Bean
public IEventSink eventSinkImpl()
{
return new InstrumentationEventSinkImpl();
}
}
Here is (a stripped-down version of) the contextInitialized() method:
#Override
public void contextInitialized( ServletContextEvent ctxEvent )
{
try
{
if (_publisher == null)
{
WebApplicationContext springContext = WebApplicationContextUtils.getWebApplicationContext(ctxEvent.getServletContext());
_eventSink = (IEventSink)springContext.getBean("eventSinkImpl");
}
_eventSink.startReceiving();
}
catch ( Exception e )
{
// handle exception
}
}
Here are the relevant entries from my 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>org.imaginary.spring.config.Instrumented</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.imaginary.MyContextListener</listener-class>
</listener>
Any ideas what I have missed?

In this case, there is nothing wrong with the Spring configuration classes or configuration. The problem was in fact a build issue - the config classes had been added to a package that wasn't getting included in the main web app jar, so the class files weren't present. I was surprised that there wasn't a NoClassDefFoundError exception thrown, as this error leaves the impression that the class exists, it just isn't annotated:
No annotated classes found for specified class/package
[your.class.here].

Related

JSF 2.3 (CDI) + Spring 4 integration

I have created a new web project from scratch using JSF 2.3 and Weld as CDI implementation running on Tomcat 9. This works all fine.
Now I would like to add a dependency to a service library (Spring 4 + Hibernate 5) which implements e.g. the user authentication against a database. This is all existing code, so it cannot be modified.
I have already read many articles, but unfortunately no one really helped me. I am facing the issue that I do not know how to inject the Spring-Bean (4.3.12.RELEASE) into a JSF-CDI managed bean.
#Named
#RequestScoped
public class AuthenticationController extends AbstractBean {
#Inject
transient private IUserService _springUserService;
#PostConstruct
public void postConstruct() {
// _springUserService is null
}
}
The service implementation class is annotated as
#Repository(IUserService.BEAN_NAME)
public class UserService implements IUserService {
//...
}
In web.xmlI have configured the spring context loader:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:spring-config-domain.xml
</param-value>
</context-param>
And in faces-config.xml I have configured the Spring-EL-Resolver
<application>
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>
So which annotation do I need to have the Spring Bean injected?
Am I missing any additional configuration for CDI in order to have it finding the Spring bean?
Thanks in advance and best regards!

spring4gwt error:Spring bean not found: querySenior

I am trying to make gwt-2.7 work with spring-4.2.3.Configurations are:
web.xml
<!-- spring config -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Spring GWT integration -->
<servlet>
<servlet-name>springGwtRemoteServiceServlet</servlet-name>
<servlet-class>org.spring4gwt.server.SpringGwtRemoteServiceServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>springGwtRemoteServiceServlet</servlet-name>
<url-pattern>/idp_web/service/*</url-pattern>
</servlet-mapping>
applicationContext.xml
<beans
...
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
....
default-lazy-init="true">
<!-- auto-inject bean by annotation mechanism -->
<context:component-scan
base-package="com.vsi.idp.analysis.server,
com.vsi.idp.base.server,
com.vsi.idp.kpi.server,
com.vsi.idp.map.server,//SeniorQueryServiceImpl is under this package
com.vsi.idp.statistics.server" />
//other configurations
</beans>
GWT services
#RemoteServiceRelativePath("service/querySenior")
public interface SeniorQueryService extends RemoteService{...}
service impl
#Service("querySenior")
public class SeniorQueryServiceImpl extends RemoteServiceServlet implements SeniorQueryService{...}
Spock unit test works fine
#ContextConfiguration(locations = "file:war/WEB-INF/applicationContext.xml")
public class SeniorQueryServiceImplTest extends Specification{
#Autowired
SeniorQueryServiceImpl service
def "query by full address"(){
//blabla
}
}
Running gwt project tells:
Failed to load resource: the server responded with a status of 500 (Server Error)
Error stack looks like:
[WARN] Exception while dispatching incoming RPC call
java.lang.IllegalArgumentException: Spring bean not found: querySenior
at org.spring4gwt.server.SpringGwtRemoteServiceServlet.getBean(SpringGwtRemoteServiceServlet.java:96)
at org.spring4gwt.server.SpringGwtRemoteServiceServlet.getBean(SpringGwtRemoteServiceServlet.java:55)
at org.spring4gwt.server.SpringGwtRemoteServiceServlet.processCall(SpringGwtRemoteServiceServlet.java:31)
at com.google.gwt.user.server.rpc.RemoteServiceServlet.processPost(RemoteServiceServlet.java:373)
I think:
1,"500(server error)" tells that gwt has recognized spring service
2,spring service unit test works fine,so spring configuration is right
The problem may come from spring4gwt,and how to solve this problem?
This really should be a working solution.
SpringGwtRemoteServiceServlet#getBean
protected Object getBean(String name) {
WebApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
if (applicationContext == null) {
throw new IllegalStateException("No Spring web application context found");
}
if (!applicationContext.containsBean(name)) {
throw new IllegalArgumentException("Spring bean not found: " + name);
}
return applicationContext.getBean(name);
}
We can see that Exception comes because there was no bean in applicationContext
Try to implicitly declare this bean in applicatinContext.
Recomendation
If you are a fun on RPC I recommend you to take a look at GWTP and their GWT dispatch module.
Approach is similar to Spring4Gwt, but it is much better to communicate with Command pattern.
With regular GWT RPC approach services in big projects becomes a mess of really lot's of
methods at one place, and you will be not happy to create a new Async pair for any new method.
Or the best approach will be to communicate with JSON and avoid GWT serialization approach, your will be happy and easy to integrate with you App later.

Strange behaviour of #Configuration with #Configurable in Spring

I've been using XML based configuration for a while - we've got a Vaadin application with Spring used as DI, but we are not interested in DispacherServlet - only root context, which we use to inject global (not user owned dependencies).
The way it works
I've defined root-context.xml file with content:
<context:annotation-config />
<context:spring-configured />
<context:load-time-weaver />
<context:component-scan base-package="com.example" />
And my web.xml has in it:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Then, some of my classes are defined with #Component annotation and others with #Configurable (the latter mostly belong to user session, so require DI for each instance created with new keyword).
I've got context.xml file with line:
<Loader delegate="false" loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader" />
And spring-instrument-tomcat-3.2.1.RELEASE.jar in Tomcat's lib directory.
All the dependencies are injected (with #Autowire) to my #Configurable classes correctly.
The way it doesn't work
Recently I've tried to get rid of root-context.xml and move context initialisation to Java #Configuration class.
I've created a class as follows:
#Configuration
#EnableSpringConfigured
#EnableLoadTimeWeaving
#ComponentScan("com.example")
public class BeansConfiguration
{
}
In addition I changed web.xml entries:
<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.example.spring.BeansConfiguration</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Unfortunately, strange things started to happen. Let me show you an example. Simplifying my class structure looks as follows:
#Component
public class ComponentA
{
}
#Configurable
public class BeanB
{
#Autowired
private ComponentA componentA;
}
#Configurable
public class BeanC
{
#Autowired
private ComponentA componentA;
private BeanB beanB;
public BeanC(BeanB beanB)
{
this.beanB = beanB;
}
}
#Configurable
public class Application
{
#Autowired
private ComponentA componentA;
public Application()
{
}
public void init()
{
BeanC beanC = new BeanC(new BeanB());
}
}
With the XML setup, when it does work, ComponentA is correctly injected by Spring into all my #Configurable objects.
Strangely, with annotation-only configuration BeanC doesn't get the ComponentA injected (it's always null), howewer BeanB and Application do get that!
Have you got any ideas why would it happen? As soon as I comment out lines in web.xml to go back to my previous (XML-based) configuration all starts to work.
My happy guess is that XML Spring entries register something more under the cover than their annotation based counterparts. I've spend half a day trying to find out, what could that be, but I gave up. I would appreciate any suggestions.

RestEasy with Spring renders no answer

I can see that the FilterDispatcher is called (by debugger), but it doesn't seem to find the service to call. I've got trouble grasping how RestEasy actually maps between resources defined in Spring and RestEasy.
Main story: Getting http://my.local.no:8087/rest/typeaheads/h only renders 404
web.xml:
...
<context-param>
<param-name>resteasy.servlet.mapping.prefix</param-name>
<param-value>/rest</param-value>
</context-param>
<listener>
<listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter>
<filter-name>restFilterDispatcher</filter-name>
<filter-class>org.jboss.resteasy.plugins.server.servlet.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
<filter-name>restFilterDispatcher</filter-name>
<url-pattern>/rest/*</url-pattern>
</filter-mapping>
...
resteasy resource is set up by bean:
#Configuration
#ComponentScan(basePackageClasses = TypeaheadsRestService.class)
public class SpringConfig {
}
TypeaheadsRestService.java:
#Resource
#Path("/typeaheads")
public class TypeaheadsRestService {
#GET
#Path("/{search}")
#Produces(MediaType.APPLICATION_JSON)
public List<NameUrl> get(#PathParam("search") String search) {
...
}
}
The RestEasy SpringContextLoaderListener seem to be the missing part. I created a stripped down problem from RestEasy example and used it. For my somewhat more complex application however it would not work. That is probably because it overrides the deprecated createContextLoader-method. In Spring 3 ContextLoaderListener is an instance of ContextLoader. So I reimplemented it like this:
public class MyContextLoaderListener extends ContextLoaderListener {
private SpringContextLoaderSupport springContextLoaderSupport = new SpringContextLoaderSupport();
#Override
protected void customizeContext(ServletContext servletContext, ConfigurableWebApplicationContext applicationContext) {
super.customizeContext(servletContext, applicationContext);
this.springContextLoaderSupport.customizeContext(servletContext, applicationContext);
}
}
I originally tried to do the customizeContext(...) in a bean initialisation. That worked in RestEasy 2.2.1.GA, but not in 2.3.4.FINAL.

Using ApplicationContext in Spring MVC.

I have a spring.xml file where in all the bean definitions are listed, where i have listed all the dependencies using beans, specified messageSource, dataSource etc. Also i have a class ApplicationContext class where iam using the context to get all the beans.
The code is ::
package models;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ApplicationContextClass {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
AbstractApplicationContext context = new ClassPathXmlApplicationContext("Spring.xml");
context.registerShutdownHook();
ATTModel attmodel = (ATTModel) context.getBean("att");
//ProjectModel project = (ProjectModel)context.getBean("project");
//project.call1();
attmodel.call();
System.out.println(context.getMessage("insertiondone",null, "Default greeting",null));
}
}
and i have Dao class where an applicationContext is used to access JDBCtemplate related bean. I have to develop a web application now using spring MVC and i need to use this applicationContext. How can i use these applicationContext classes in SpringMVC. I knw i need to use applicationcontextlisteners but where to write them ? Thanks..
You have two ways. In web.xml define this.
<servlet>
<servlet-name>yourapp</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
And to your WEB-INF folder add yourapp-servlet.xml with your beans and mvc configuration.
Other way is. In web.xml define this.
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
And to your WEB-INF add applicationContext.xml with your beans.
You can also combine these approaches.

Resources