Spring integration helper class

I’ve come up with (IMHO) a somewhat cleaner way to integrate with Spring than shown in the FAQ (see
ticket #4132
) . I’m curious if other folks have comments.

The basic idea is if
com.example.MyApplication
is your
Application
subclass, then you use this new class
AutowiringApplicationServlet
(visible
here
)to automatically wire up your application:


  <bean id="applicationServlet" class="org.springframework.web.servlet.mvc.ServletWrappingController"
     p:servletClass="com.example.AutowiringApplicationServlet">
      <property name="initParameters">
          <props>
              <prop key="application">com.example.MyApplication</prop>
          </props>
      </property>
  </bean>

When it gets created, your MyApplication will be automatically configured from the containing application context, i.e., any
@Autowired
,
@Required
annotations and interfaces such as
BeanFactoryAware
will be respected, just as if the bean had been defined directly in the application context.

This is the cleanest and simplest way to do it I’ve found… are there even better/cleaner ways out there? Thanks.

You can autowire your Application class as your example shows, but how about other classes? In a large web app, you will no doubt have a lot of CustomComponents and other classes which you will need to autowire.

There’s a project in incubator which uses the same methods you do. It provides autowiring by passing a SpringAwareApplication reference through constructors which take care of the autowiring:

http://dev.vaadin.com/browser/incubator/SpringIntegration/trunk

Just a while back I was considering on improving the project by making the autowiring through a static method which has access to Spring. But then I got the context:spring-configured to work with help from Petri Hakala and Henri Sara and it’s been a lot easier to work with. Here’s a thread where we discussed it:

http://vaadin.com/forum/-/message_boards/message/80732

In short, the FAQ way feels superior to me.

You just stick them in your application context… the same one (or a parent).

In other words, everything is setup just like a normal Spring MVC web application, with ContextLoaderListener, DispatcherServlet, etc. The
AutowiringApplicationServlet
just serves to connect your
Application
to the Spring context that it’s already living within.

Here’s the setup I’m using:


web.xml
  |
  +-- ContextLoaderListener
  |      |
  |      +-- applicationContext.xml      <-----+
  |           |                                |
  |           +-- Hibernate SessionFactory     |
  |           |                                |
  |           +-- DAO beans                 parent
  |           |                                |
  |           +-- Whatever other beans         |
  |                                            |
  +-- DispatcherServlet                        |
        |                                      |
        +-- dispatcher-servlet.xml       >-----+
              |
              +-- ServletWrappingController
              |     |
              |     +-- AutowiringApplicationServlet
              |          |
              |          +-- MyApplication
              |
              +-- SimpleUrlHandlerMapping
              |
              +-- Whatever other beans

This is the normal Spring MVC setup.

The Vaadin Application (
MyApplication
in the example) acts just like any other bean in the
dispatcher-servlet.xml
application context. Everything works just like a normal Spring MVC setup… which is the whole point, right?

Specifically, this kind of thing works:


public class HelloWorld extends Application {

    @Autowired
    private UserDAO userDAO;

    @Override
    public void init() {
        Window mainWindow = new Window("HelloWorld Demo");
        Label label = new Label("userDAO = " + this.userDAO);
        mainWindow.addComponent(label);
        setMainWindow(mainWindow);
    }
}

For completeness, here’s some snippets from
web.xml
:


    <!-- Spring context loader -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- Spring dispatcher servlet -->
    <servlet>
        <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>/myapp/*</url-pattern>
    </servlet-mapping>

and
applicationContext.xml
:


    <!-- Hibernate session factory -->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"
      p:dataSource-ref="dataSource" p:configLocation="classpath:hibernate.cfg.xml">

    <!-- Find DAO beans -->
    <context:component-scan base-package="com.example.dao.hibernate"/>

and
dispatcher-servlet.xml
:


    <!-- Spring annotation support -->
    <context:annotation-config/>

    <!-- Vaadin application servlet -->
    <bean id="helloWorldController" class="org.springframework.web.servlet.mvc.ServletWrappingController"
      p:servletClass="com.example.AutowiringApplicationServlet">
        <property name="initParameters">
            <props>
                <prop key="application">com.example.HelloWorld</prop>
                <prop key="productionMode">true</prop>
            </props>
        </property>
    </bean>

    <!-- Map URIs to web controllers -->
    <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="urlMap">
            <map>
                <entry key="/hello" value-ref="helloWorldController"/>
                <entry key="/UIDL/**/*" value-ref="helloWorldController"/>
            </map>
        </property>
    </bean>

Again, this is all just the normal (to me anyway) Spring MVC setup.

Archie, would you mind posting complete versions of your .xml files (web, applicationContext and dispatcher-servlet) for your example?

I’m new to Spring MVC (but not to Spring), Web applications and Vaadin, and I’m having trouble getting an example based on your post running. Everything appears to be created properly (logging shows all the beans are being created), but when Vaadin runs the application class, it dies on a NullPointerException, because a bean that should have been injected into the main class is not there.

I’m wondering if I’ve got something my versions of the files that is messing something up, or maybe I’m missing something?

Thanks, Maury

I managed to figure it out. As I suspected, I had extra code in the web.xml files that was getting in the way. Specifically, I still had the default Vaadin entries in the file. Once I removed those, things were working as expected.

I would still like to see your .xml files, though.

Thanks, Maury

Sure… I’ve built a little example project that builds a WAR file. See attachment to this post.

-Archie
11205.zip (13.5 KB)

Very interesting.

There are definite upsides to this kind of integration. One thing I really like is that you don’t need to mess with application wide xml configuration just to integrate with Vaadin, it acts like just another servlet. This should make it easier to add Vaadin to existing projects and use other technologies besides Vaadin.

Thumbs up for you Archie!

Thanks Archie. I’ve downloaded the file and I’ll be looking at it later.

Maury

FYI,

The
demo.zip
that I uploaded demonstrates the Spring “MVC” approach using the
DispatcherServlet
, URL mappers, and Spring “controller” beans.

You can also do a simpler thing, which is to map the
AutowiringApplicationServlet
directly into your
web.xml
. With this approach, you still get your
applicationContext.xml
thanks to Spring’s
ContextLoaderListener
, but there’s no
DispatcherServlet
involved… and so your
web.xml
just looks like this:


<web-app xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
  version="2.5">

    <display-name>Vaadin+Spring Demo #2</display-name>
    <description>Vaadin+Spring Demo #2</description>

    <!-- Spring context loader -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- Vaadin servlet -->
    <servlet>
        <servlet-name>hello</servlet-name>
        <servlet-class>com.example.AutowiringApplicationServlet</servlet-class>
        <init-param>
            <param-name>application</param-name>
            <param-value>com.example.HelloWorld</param-value>
        </init-param>
        <init-param>
            <param-name>productionMode</param-name>
            <param-value>false</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

</web-app>

This eliminates the “extra hop” through the
DispatcherServlet
.

I’ve attached this even simpler example as
demo2.zip
.

-Archie
11208.zip (12.3 KB)

Thanks Archie!

Those solutions looks very good for me also. Tomorrow I have to test that demo2 with vaadin Portlet 2.0. I am trying to get my Service connected to application class.

Hi

I am new to Vaadin. My current application uses spring mvc, security etc. Before I invest time in Vaadin, I want to know any problem to integrate spring mvc and spring security with Vaadin.

thanks a lot for any feedback!


Here
is one way of doing Spring integration. There is also
others
.

Archie,

Absolutely wonderful. I just started investigating Vaadin, and I did NOT like the idea of having to rework my entire application just to integrate it. Right now, everything in my app goes through Spring Framework, Spring MVC and Spring Security, and I didn’t want to have to invert things by making a Vaadin-based servlet be the main dispatcher. I only plan on sprinkling parts of my application with Vaadin and leaving everything else alone, so by doing it your way I get the best of both worlds. IMHO, it should go like this: Spring → Vaadin, and not Vaadin → Spring.

Thank you so much for the integration work.

Regards,
Michael

Thanks for the idea!

Here’s the same for Portlet 2.0 env.


package foo.bar;

import javax.portlet.*;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.web.portlet.context.PortletApplicationContextUtils;

import com.vaadin.Application;
import com.vaadin.terminal.gwt.server.AbstractApplicationPortlet;

public class AutowiringApplicationPortlet extends AbstractApplicationPortlet {
	private ApplicationContext springContext;
	private Class<? extends Application> applicationClass;
	
	@Override
	public void init(PortletConfig config) throws PortletException {
		super.init(config);
		springContext = PortletApplicationContextUtils.getRequiredWebApplicationContext(config.getPortletContext());
		
		final String applicationClassName = config.getInitParameter("application");
		if (applicationClassName == null) {
			throw new PortletException("Application not specified in portlet parameters");
		}
		try {
			applicationClass = (Class<? extends Application>) getClassLoader().loadClass(applicationClassName);
		} catch (final ClassNotFoundException e) {
			throw new PortletException("Failed to load application class: "+applicationClassName);
		}
	}
	
	protected ApplicationContext getSpringContext() {
		return springContext;
	}
	
	protected final AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws PortletException {
		try {
			return getSpringContext().getAutowireCapableBeanFactory();
		} catch (IllegalStateException e) {
			throw new PortletException("Containing context "+getSpringContext()+" is not autowire-capable", e);
		}
	}
	
	@Override
	protected Class<? extends Application> getApplicationClass() {
		return applicationClass;
	}
	
	@Override
	protected Application getNewApplication(PortletRequest request) throws PortletException {
		Class<? extends Application> clazz = getApplicationClass();
		try {
			return (Application) getAutowireCapableBeanFactory().createBean(clazz);
		} catch (BeansException e) {
			throw new PortletException(e);
		}
	}
}

And to portlet.xml


<portlet>
	<portlet-name>foo</portlet-name>
	<display-name>bar</display-name>
	<portlet-class>[b]
foo.bar.AutowiringApplicationPortlet
[/b]</portlet-class>
	<init-param>
		<name>application</name>
		<value>foo.bar.ApplicationClass</value>
	</init-param>
	<init-param>
		<name>widgetset</name>
		<value>com.vaadin.portal.gwt.PortalDefaultWidgetSet</value>
	</init-param>
	<supports>
		<mime-type>text/html</mime-type>
		<portlet-mode>view</portlet-mode>
	</supports>
	<supported-locale>en-US</supported-locale>
	<supported-locale>fi</supported-locale>
</portlet>

(Sorry for reviving this thread, if anyone takes offense)

What about the scope of these Vaadin components when you have them managed by Spring? Surely they’d have to be scoped on “prototype” in order not to share component state across sessions? Will everything be cleaned up correctly when sessions expire?

That’s fine. Forum is open for everyone and everyone is welcomed to comment.

Indeed you are right here. Although the original approach (configuration files, AutowiringApplicationServlet) aim to populate application-wide beans (like services) into Vaadin application. But of course you can use Spring to create session-wide beans, and you need “prototype” option for these beans. In my application I need to create several objects per session, so I use “ApplicationContext” injected into my application and create beans manually.

I hope the once day the real support for “session” type will be added.

Hi,

I’m happily using session scoped beans in Vaadin.

All I’ve done is added spring’s RequestContextListener to web.xml, defined the bean to be injected with the scope of session in my spring beans file, and marked it as autowired in the code.

Example :

web.xml:
<listener>
    <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>

application-context.xml:
<bean scope="session" class="org.bushe.swing.event.ThreadSafeEventService"/> 

WindowWithEventService.java:
@Configurable(preConstruction = true, dependencyCheck = true)
protected class WindowWithEventService extends Window {
   @Autowired(required = true) 
   protected transient EventService eventService;
}

So far, it’s worked like a dream.

Cheers,

Charles

Hi Charles,

Thank you for example. I believe, you also have
org.springframework.web.context.ContextLoaderListener
in your web.xml to create Spring application context on Web application startup. I am not familiar with
RequestContextListener
, but from Javadocs I got that this class exposes the request attributes (e.g.
HttpServletRequest
and
HttpSession
objects) to application via thread local variable so that they are available within the lifespan of request. I have not found any direct relation between that class and support of “session”-scoped beans. One need something that will create
WebApplicationContext
instance and I know only one class capable to do this:
org.springframework.web.servlet.DispatcherServlet
. So:

  • If you use
    DispatcherServlet
    in your web.xml and forward the requests to Vaadin servlet, then everything is clear. But you don’t need
    ContextLoaderListener
    then.
  • If you don’t use it and dispatch all requests to Vaadin – there is some magic behind. I wonder, who creates the Web Context then?

Hi Dmitry,

Yes, this is true.

We don’t.

[quote]
If you don’t use it and dispatch all requests to Vaadin – there is some magic behind. I wonder, who creates the Web Context then?
[/quote] I’m pretty sure it’s the RequestContextListener but I could be wrong. [1]

Honestly, in my simple world (!), I just
a) added the ContextLoaderListener & RequestContextLoaderListener to web.xml
b) configured the ContextLoaderListener with the spring XML files
c) added the autowire stuff to my code

And away I went.

I am using loadtime weaving, if that’s relevant. Not sure it is, though… Maybe I should knock together a simple project.

Cheers,

Charles.

[1]

Some Time Later

I can confirm that it is the RequestContextListener that’s sprinkling some magic pixie dust over the setup. If I comment it out of my web.xml, I get the following exception - which is clearly where I found out that I had to add the RequestContextListener!

java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:123)
org.springframework.web.context.request.SessionScope.get(SessionScope.java:90)
org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:325)
org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:190)
org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:844)
org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:786)
org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:703)
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:478)
org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:84)
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:283)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1074)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:374)
org.springframework.beans.factory.wiring.BeanConfigurerSupport.configureBean(BeanConfigurerSupport.java:140)
org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect.configureBean(AnnotationBeanConfigurerAspect.aj:59)
org.springframework.beans.factory.aspectj.AbstractDependencyInjectionAspect.ajc$before$org_springframework

Just to (hopefully) clarify a little bit…

The
ContextLoaderListener
is a servlet context listener that associates a Spring application context with your servlet context and makes it accessible to other Spring classes. Typically this is defined via an
applicationContext.xml
file that sits in
WEB-INF
.

The
RequestContextListener
is a servlet filter that, at the start of each request, stuffs a reference to the request object etc. in a private ThreadLocal variable so that other Spring classes that want to answer the question “what is the current HTTP request associated with this thread?” can get the answer to that question by invoking the appropriate static method.

The
DispatcherServlet
is a regular Java servlet that Spring provides. Each such servlet has its own Spring application context - distinct from, though a “child” of, the one mentioned above associated with the
ContextLoaderListener
. If your servlet is named
foobar
then the default XML file name is
foobar-servlet.xml
.

The autowiring of your Vaadin application using the
AutowiringApplicationServlet
can be done at either level, i.e., using the
ContextLoaderListener
context or using the
DispatcherServlet
context. Examples of both are given in previous posts to this thread (
here
and
here
, respectively).

Regarding session scope, this is supported by Spring and works just fine, and does not have any direct interaction with whether you are using Vaadin or not. Of course, Vaadin applications are also “session scoped”, so there is a natural usage correspondence.

In my own experience, I have not used session scoped Spring beans much. Instead, I usually end up having almost all beans be stateless singletons, such as DAO’s and service beans.