DWR and Spring

Initial considerations

DWR / Spring integration has changed a lot with time and not all the different configurations are always available.

  1. Make sure you are on the latest DWR. The Spring creator has changed so it is well worth checking that you have the latest download.
  2. Make sure you are happy with everything on the getting started page.
  3. Make sure your Spring beans work properly outside of DWR (unit test).
  4. Select the configuration style based on your Spring version (see below).
  5. Configure DWR to work with Spring (see below).
  6. Look at the demo pages: http://localhost:[PORT]/[YOUR-WEBAPP]/dwr to check that your spring beans appear.

DWR 1.x - dwr.xml - The Spring creator

If you feel comfortable using dwr.xml or you are still using DWR 1.x, you will need 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:

  • Spring MVC

    Define a DispatcherServlet and declare the beans in <dispatcher>-servlet.xml. There are no specifics for DWR remoted beans.
  • ContextLoaderListener

    For other MVC frameworks. Please read the documentation.
  • Using location* parameters

    If you prefer to specify which beans.xml to use in your dwr.xml file then you can use a location* parameter. You can specify as many as you wish although the names must be unique and start 'location'. For example: location-1, location-2. These locations are used as parameters to a Spring ClassPathXmlApplicationContext:
    <allow>
      ...
      <create creator="spring" javascript="Fred">
        <param name="beanName" value="Shiela"/>
        <param name="location" value="beans.xml"/>
      </create>
      ...
    </allow>
    
  • Setting the BeanFactory directly

    The SpringCreator has a static setOverrideBeanFactory(BeanFactory) method that provides a way to programatically override any BeanFactories found by other means (if any).

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.

DWR 2.0.x - Spring 2.0.x - The DWR namespace handler

Spring 2.x includes a new feature named XML Namespace Handlers. This allows DWR when working with Spring MVC to remote Spring beans easily with a custom syntax. If you're not using the MVC module, you can still leverage the namespace by mapping an org.directwebremoting.spring.DwrSpringServlet in your web.xml.

<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>

The namespace

The first task you need to accomplish is adding the following lines (in bold, bellow) 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.0.xsd
    http://www.directwebremoting.org/schema/spring-dwr
    http://www.directwebremoting.org/schema/spring-dwr-2.0.xsd">
.

Once you have added the namespace declaration any modern IDE (NetBeans, Eclipse, Idea) will automatically help you to write the tags with its code completion features.

The configuration tag

You must declare one <dwr:configuration> tag. This tag is mandatory even if empty. It may have nested tags (init, creator, signatures,..). These nested tags mimic the behavior of those available in dwr.xml. Understand their functioning first and then use your IDE to translate to the correct syntax.

The controller tag

Again you must declare one <dwr:controller id="dwrController" debug="true" /> tag. This tag does not allow inner tags. In Spring MVC, for each controller you have to map the URLs that it will handle. The simplest way is probably declaring a SimpleUrlHandlerMapping. DWR needs mappings for the following URLs: /engine.js, /interface.js, /call/**, /interface/**. Remember that a DWR Controller is just needed (and useful) in Spring MVC environments (use the servlet in other cases) and this way you get the number of other related Spring services (ie localization).

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>

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.

  • Always declare and implement an interface with the remoted methods.
  • Remember to include <aop:scoped-proxy proxy-target-class="false" /> in the bean declaration

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 these things:

  • You have an interface and an implementation
  • You have declared <aop:aspectj-autoproxy proxy-target-class="false" />in your Spring XML
  • You have decorated your remoted bean with <aop:scoped-proxy />
In fact, AOP proxies work fine with DWR. Just configure Spring accordingly.

Beyond the documentation

This kind of integration has been discussed in depth some times by now. Try reading:

The future

New configuration options are already committed in CVS. They're available today for those who like living on the edge (development). The most important are the automatic mapping of URLs (<dwr:url-mapping />)and the use of annotations to remote Spring beans (<dwr:annotation-config />). As you can see, they make even further use of the namespace feature. They will be properly documented here with the new release. This new features require Spring 2.5 at least.