DWR and Spring

Initial considerations

  1. Make sure you have the appropriate version of Spring. DWR 3 requires Spring version 2.5 or greater.
  2. Make sure you understand everything on the getting started with DWR page.
  3. Make sure your Spring beans work properly outside of DWR (unit test).
  4. Select your configuration style based on the version of Spring you are using, etc. (see below).
  5. Configure DWR to work with Spring (see below).
  6. Check the DWR generated test page: http://localhost:[PORT]/[YOUR-WEBAPP]/dwr/index.html to make sure your spring beans appear.

Step 1 - Give DWR access to the Spring context

In order to integrate DWR with Spring, DWR needs to gain access to the Spring context. There are two options here:

  1. Use Spring MVC
  2. Use the DWRSpringServlet

Use Spring MVC

If you are using Spring MVC your web.xml should look something like this:

<servlet>
  <servlet-name>springDispatcher</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value> classpath:yourSpringContext.xml</param-value>
  </init-param>
  <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>springDispatcher</servlet-name>
  <url-pattern>*.html</url-pattern>
</servlet-mapping>
<servlet-mapping>
  <servlet-name>springDispatcher</servlet-name>
  <url-pattern>/dwr/*</url-pattern>
</servlet-mapping>

The only thing you need to add is the mapping of /dwr/* to the Spring dispatcher servlet. If you are mapping your dispatcher servlet to / or /*, you will still need the /dwr/* mapping and it must be defined before the global mapping. Please see our common problems section for more details.

A complete working example of this configuration can be found here.

Use the DWRSpringServlet

The DwrSpringServlet can be used if you are not using Spring MVC. This servlet gains access to the Spring context configured in your web.xml. Example web.xml:

<listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>
    classpath:yourSpringContext.xml
  </param-value>
</context-param>
<servlet>
  <servlet-name>dwr</servlet-name>
  <servlet-class>org.directwebremoting.spring.DwrSpringServlet</servlet-class>
  <init-param>
    <param-name>debug</param-name>
    <param-value>true</param-value>
  </init-param>
</servlet>
<servlet-mapping>
  <servlet-name>dwr</servlet-name>
  <url-pattern>/dwr/*</url-pattern>
</servlet-mapping>

A complete working example of this configuration can be found here.

Step 2 - Configure DWR's remoting

The next and final step is to configure DWR's remoting - once again there are several options. In the past (3 below) this step was accomplished in the dwr.xml via Creators and Converters. However, Spring 2.x introduced a new feature named XML Namespace Handlers. This allows DWR and Spring MVC to remote Spring beans easily with a custom syntax and removes the need for dwr.xml. Configuration for the custom namespace is covered in 1 and 2 below.

  1. Use the DWR/Spring namespace (Spring 2.5 or greater, DWR 2.x or greater, dwr.xml not required or recommended)
  2. Use the DWR/Spring namespace with annotations (Spring 2.5 or greater, DWR 2.x or greater, dwr.xml not required or recommended)
  3. Use the Spring Creator (Will work for older versions of Spring or DWR - dwr.xml required. Not the recommended approach.)

The namespace

The first task you need to accomplish is adding the following lines (in bold, below) to any of your Spring XML files that includes at least one DWR specific tag. Add them inside the beans declaration (at the beginning of the file):

<beans
  xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:dwr="http://www.directwebremoting.org/schema/spring-dwr"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
    http://www.directwebremoting.org/schema/spring-dwr
    http://www.directwebremoting.org/schema/spring-dwr-3.0.xsd">
Please continue reading for an overview of some of the critical features of the DWR/Spring schema. To view the complete capabilities you may want to view the schemas directly - For DWR 3.x users spring-dwr-3.0.xsd - For DWR 2.x users spring-dwr-2.0.xsd.

The controller tag

If you are not using Spring MVC - skip this section. The controller tag only applies to Spring MVC configurations.

If you are using Spring MVC you must declare one <dwr:controller id="dwrController" debug="true" /> tag.

  <dwr:controller id="dwrController" debug="true"/>
You may also specify configuration parameters for the dwrController:
  <dwr:controller id="dwrController" debug="true">
    <dwr:config-param name="activeReverseAjaxEnabled" value="true"/>
  </dwr:controller 

In Spring MVC, for each controller you have to map the URLs that it will handle. The simplest way to do this is by using the <dwr:url-mapping /> tag. If you use the url-mapping tag the DWR test page will be unavailable.

Alternatively, you may specify your own SimpleUrlHandlerMapping. DWR needs mappings for the following URLs: /engine.js, /interface.js, /call/**, /interface/**. An example of a SimpleUrlHandlerMapping that will allow the DWR test page to work can be found here (see step 2, numbered item 3). Spring mappings can be tricky. Please see our section on mappings if you are having problems.

The configuration tag

The <dwr:configuration/> is used to mimic the behavior of the configuration available in dwr.xml. This tag is optional and it may have nested tags (init, creator, signatures,..). These nested tags mimic the behavior of those available in dwr.xml. Example:

  <dwr:configuration>
    <dwr:convert type="bean" class="org.uk.ltd.dwr.dev.model.Address" />
  </dwr:configuration>

The remote tag

Inside each bean you want to remote include a <dwr:remote javascript="Fred"> tag. There you can specify the methods that are going to be proxied and those that won't. For example:

<bean id="timeConvert" class="com.mycompany.ui.util.TimeConvert">
  <dwr:remote javascript="AjaxTimeConvert">
    <dwr:include method="convert" />
  </dwr:remote>
</bean>

Exposing beans in other application contexts - the proxy-ref element

It is also possible to remote a bean already defined in a reachable application context indicating the reference to it by using the proxy-ref element.

Two complete (one with Spring MVC, one without) working examples of DWR and Spring using the namespace can be found here.

The namespace with Annotations

Before attempting to integrate DWR and Spring with annotations you should be familiar with the DWR/Spring namespace. Below is a listing of the most important DWR annotations and their functional namespace equivalents:

If you would like to use annotations to remote your Spring beans DWR provides two tags that make it easy.

  1. annotation-scan - Enables DWR to scan the classpath and:
    • Detect beans annotated with @RemoteProxy & @RemoteMethod, and register the Spring beans and DWR Creator proxies for them. Because DWR is registering the beans into the Spring context for you all Spring annotated beans (@Service, @Component, @Controller, etc.) will be ignored to avoid duplicate registration.
    • Detect DWR converters annotated with @DataTransferObject.
    This element has several available attributes:
    • base-package - The base package to initiate scanning from - i.e. com.myApp.*.
    • regex - A regular expression that will be used in the classpath scanner.
    • scanRemoteProxy - Should DWR scan for remote proxies? Defaults to true.
    • scanDataTransferObject - Should DWR scan for converters? Defaults to true.
    • scanGlobalFilter - Defaults to true.

    A complete working example of a dwr:annotation-scan configuration can be found here.

  2. annotation-config - Enables DWR to scan the Spring context, detect beans annotated with @RemoteProxy & @RemoteMethod and register the DWR Creator proxies for them.

Annotations - An example of the configuration required for a typical use-case
  <dwr:annotation-config id="dwrAnnotationConfig" />
  <dwr:annotation-scan base-package="com.yourpackage.whatever" scanDataTransferObject="true" scanRemoteProxy="false" />

In the example above:

  1. The dwr:annotation-config tag scans the Spring context and adds DWR creator proxies for beans annotated with @RemoteProxy.
  2. The dwr:annotation-scan tag scans the classpath and adds DWR converters for all beans annotated with @DataTransferObject. We have disabled the scanning for remote proxies - in this case it is assumed the DWR creator proxies are existing beans in the Spring context and the dwr:annotation-config tag will add them.

The Spring Creator and dwr.xml

If you feel comfortable using dwr.xml you may use the Spring creator. This creator will lookup beans in your Spring <beans>.xml file and rely on Spring to instantiate them. This creator will be useful to you if you already use Spring and totally useless if you don't.

You allow DWR to use the spring creator to create and remote your beans as follows:

<allow>
  ...
  <create creator="spring" javascript="Fred">
    <param name="beanName" value="Shiela"/>
  </create>
  ...
</allow>

There are several ways to find your spring configuration files:

Please, take into account that not all methods are equally easy in practice. Probably, unless you know what you're doing you're better served using one of the first two.

Common Problems

Scoped Beans

One of the common pitfalls when integrating Spring and DWR are scoped beans (session, request, ...). In practice is easy to get them going, just remember two basic rules.

Here's an example:

<bean id="calc" class="...CalculatorImpl" scope=session>
  <dwr:remote javascript="Calculator">
    <dwr:include method="add"/>
  </dwr:remote>
  <aop:scoped-proxy proxy-target-class="false" />
</bean>

Aspects & DWR

If you're receiving the dreaded object is not an instance of declaring class error always check the following:

In fact, AOP proxies work fine with DWR. Just configure Spring accordingly.

Mappings! Mappings! Mappings!

It is important to note that the creation of the SimpleUrlHandlerMapping may cause your existing mappings to fail if you have not explicitly created a Handler Mapping in your Spring configuration. By default Spring creates a BeanNameUrlHandlerMapping if you have not explicitly created a Handler Mapping. So when the SimpleUrlHandlerMapping is created for DWR, Spring will no longer create the default BeanNameUrlHandlerMapping and existing mappings will not work. Spring allows you to have multiple Handler Mappings, to fix this you need to create a BeanNameUrlHandlerMapping explicitly in your spring.xml (in addition to the SimpleUrlHandlerMapping). See the Spring documentation section 13.4.1 for more information.

Id is required for element 'annotation-config' when used as a top-level tag

This appears to be happening with Spring 3.x and above. We use a Spring class to parse the annotation-config element and if you do not specify an id the parser is unhappy. For now a solution to this appears to be simply adding an id attribute.

/ or /* Spring MVC Dispatcher Mapping

If you have mapped Spring MVC's dispatcher servlet to / or /* you will run into issues with DWR. Example (don't do this):

<servlet>
  <servlet-name>springDispatcher</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value> classpath:yourSpringContext.xml</param-value>
  </init-param>
  <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>springDispatcher</servlet-name>
  <url-pattern>/</url-pattern>
</servlet-mapping>
This mapping is problematic for DWR. The problem arises when Spring sends the request to the DWR Controller Servlet - the path info will be null due to the / or /* mapping. This situation will prevent DWR from functioning properly. To resolve this issue always include a /dwr/* mapping before any root mappings (/, /*, etc.). Example (do this):
<servlet>
  <servlet-name>springDispatcher</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value> classpath:yourSpringContext.xml</param-value>
  </init-param>
  <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>springDispatcher</servlet-name>
  <url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
  <servlet-name>springDispatcher</servlet-name>
  <url-pattern>/</url-pattern>
</servlet-mapping>