July 17th, 2009

Non invasive GWT and Spring integration (reloaded)

New project layout

New project layout

Here is my overdue update to my Non invasive GWT and Spring integration blog post from early 2008. Since then we have had the GWT 1.6 and GWT 1.7 releases:

One of the biggest changes to GWT 1.6 is a new project structure. The old output format has been replaced by the standard Java web app "expanded war" format, and the actual directory name does default to "/war". Note that the war directory is not only for compiler output; it is also intended to contain handwritten static resources that you want to be included in your webapp alongside GWT modules (that is, things you'd want to version control).

As a matter of fact, now we finally can (must) manage the web.xml file ourselves:

Projects with server-side code (GWT RPC) must configure a web.xml file at /war/WEB-INF/web.xml. This web.xml file must define and publish any servlets associated with the web application.

This is a little pain for really much gain, and that's why I am writing this post after all...

Starting a Springframework ApplicationContext in a Java EE compiient web-application is well known and documented in the Springframework reference:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">
 
<web-app>
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring-conf.xml</param-value>
	</context-param>
	<context-param>
		<param-name>log4jConfigLocation</param-name>
		<param-value>/WEB-INF/log4j.xml</param-value>
	</context-param>
	<listener>
		<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
	</listener>
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
 
	<!-- Servlets... -->
 
	<!-- Default page to serve.. -->
 
 
</web-app>

There aren't many beans in my spring configuration files as I am using annotation based configuration in my apps. Here a sample spring confuguration taken from one of my sample projects:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="UTF-8"?>
<beans 
    xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="
	     http://www.springframework.org/schema/beans     http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
         http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-2.5.xsd
    "
	>
 
	<context:annotation-config />
	<context:component-scan base-package="x.y.gwt.hellospring.server" />
 
	<bean id="basicTextEncryptor" class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor">
		<property name="algorithm" value="PBEWithMD5AndDES" />
		<property name="keyObtentionIterations" value="1000" />
		<property name="password" value="s0990w8eh0c8hf08aefh8hGf9egf9aefea8f" />
	</bean>
 
</beans>

So this is (despite of the missing log4j.xml config) the configuration setup I am using on GWT 1.6 and GWT 1.7 projects in order to bootstrap an application context.

The next step is to implement the dependency injection of spring managed beans into my GWT RPC serverside implementation. I will be using the annotation based config provided by the Springframework.

This is how the dependency injection in my GWT RPC services looks like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
 * The server side implementation of the RPC service.
 */
@SuppressWarnings("serial")
public class EncodingServiceImpl 
extends AutoinjectingRemoteServiceServlet
implements EncodingService {
 
	private IEncodingService encodingService;
 
	@Autowired
	@Required
	public void setEncodingService(IEncodingService encodingService) {
		this.encodingService = encodingService;
	}
 
	// Service implementation ommited here...
 
}

EncodingServiceImpl is the server side GWt RPC implementation, while EncodingService is the GWT service I am setting up. The managed bean in my spring configuration implements IEncodingService (and uses the great jasypt lib). I am using the annotations to configure the dependency injection.

All I have to do now, is "autowire" my RPC servlet during initialization. Since this is not going to be the only GWT RPC service needing dependency injection I introduced the AutoinjectingRemoteServiceServlet class:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class AutoinjectingRemoteServiceServlet extends RemoteServiceServlet {
 
	@Override
	public void init(ServletConfig config) throws ServletException {
		super.init(config);
		WebApplicationContext ctx = WebApplicationContextUtils
				.getRequiredWebApplicationContext(config.getServletContext());
		AutowireCapableBeanFactory beanFactory = ctx
				.getAutowireCapableBeanFactory();
		beanFactory.autowireBean(this);
	}
 
}

There is not much to say about this class. During the initializiation of the RPC Servlet (remember: GWT uses servlets as the foundation technology on the server side implementation of GWT RPC. Being so, the GWT RPC service implementation "lives" in the same lifecycle as any other servlet. I am using the initialization step to get a reference to the ApplicationContext. After that I use the autowire bean method to autowire the servlet automatically.

If you prefer to directly expose spring beans, you should have a look at http://code.google.com/p/spring4gwt/.

9 comments to Non invasive GWT and Spring integration (reloaded)

  • Sorry, having troubles with XML code snippets and the layout… Hope to get it fixed soon…

  • Hello, P.G.,

    Thank you for the post. I like the way you use Spring auto-injecting with GWT RPC, am going to give it a try. On my website, http://minetats.com , I have another example on how one could use GWT and Spring together – a menu-driven web application. I use commands on both client and server sides. On the server, I use ServiceLocatorFactoryBean as well as Spring Security (with a GWT-driven login page). Please take a look if interested.

    Thanks,
    Alec Missine

  • Michael

    Hi Alec,

    nice example application. Would it be possible to download the whole example as a (Eclipse) project? This would be more comfortable than downloading the individual files (btw clicking on “spring-security.xml” shows an alert “not implemented”).

    Thanks,
    Michael

  • [...] Non invasive GWT and Spring integration (reloaded) [...]

  • Sam Brodkin

    Thanks P.G. This is indeed the most straightforward way to go.

    I have uploaded a full implementation of the ideas in this article here:

    http://code.google.com/p/gwt-spring-starter-app/

    It’s simply the greeting app you get when you use the GWT webAppCreator but then modified according to your article.

  • Before you start using GWT-RPC, give it a second thought by having a look here:

    http://pgt.de/2009/09/18/best-practices-for-architecting-your-gwt-app/

  • Thanks for a simple yet effective method! Though, I had to fix it a bit – using autowireBeanProperties instead of autowireBean, otherwise my services didn’t get populated.

  • Hi Constantine,

    you are welcome, I am glad it fits you need.
    From the Spring API:

    autowireBean( Object existingBean )

    Populate the given bean instance through applying
    after-instantiation callbacks and bean property
    post-processing (e.g. for annotation-driven injection).

    autowireBeanProperties(Object existingBean, int autowireMode, boolean dependencyCheck)

    Autowire the bean properties of the given bean instance by name or type.

    Well, “autowireBean” worked properly for me, can’t tell why it did not work for you.

  • Hans

    Anyone found a solution to use this in Spring 2.1 yet?

Leave a Reply