Bean and Object Converters

Overview

Two converters that are not enabled by default are the Bean and Object converters. They will convert Java Beans and POJOs to and from JavaScript objects. These converters are not enabled by default because DWR makes sure that is has permission before it exposes any of your classes.

The Bean converter will expose properties on your classes based upon getters and setters. The Object converter is similar except that it works on data members directly. All classes need to be concrete and have a default constructor, though non-concrete types (interfaces and abstract classes) may be used as method arguments when using the class mapping feature described later on this page. All the examples below work using 'object' in place of 'bean' to use direct member access.

Security note: If you are enabling conversion of a bean that has a constructor or setter that has some nasty side effects, then it would be possible for an attacker to take advantage of this side effect as the constructor and setters are executed during the DWR incoming data conversion.

You can enable the bean converter for a single class using the following:

<convert converter="bean" match="com.example.Person"/>

To allow conversion of any class in the given package:

<convert converter="bean" match="com.example.*"/>

To allow conversion of any class in the given package and all sub-packages:

<convert converter="bean" match="com.example.**"/>

BeanConverter and the JavaBeans Specification

Beans converted using the BeanConverter need to follow the JavaBeans spec because the converter uses Introspection and not Reflection. This means things like having properly named getters and setters where there is a single parameter to the setter which matches the return type of the getter. The setter should return void, the getter should not have any parameters and there is no overloading of setters. Mostly this is common sense, but it does trip some people up. If your class does not follow the Java Bean specification then you need the ObjectConverter.

Supplying parameters in calls from Javascript

Apart from converting Java objects into JavaScript objects (aka maps, aka associative arrays) when returning data to the browser, DWR will convert Javascript objects into Java objects when making calls from the browser.

A quick example may help. Suppose you have the following Java code:

public class Remoted {
  public void addToFriends(Person p) {
    // ...
  }
}

public class Person {
  public void setName(String name) { ... }
  public void setAge(int age) { ... }
  // ...
}

If Remoted was configured as a Creator, and Person is convertable using the BeanConverter, then you can make the call from JavaScript as follows:

var p = { name:"Fred", age:21 };
Remoted.addToFriends(p);

Restricting Property Conversion

Just as you have exclude and include for creators to instruct DWR to exclude methods, there is a similar system for converters.

Since restricting property conversion only makes sense for Beans (clearly primitive types don't need restrictions on conversion of their properties) this functionality is specific to BeanConverter and anything that inherits from it (like HibernateBeanConverter)

The syntax is:

<convert converter="bean" match="com.example.Person">
  <param name="exclude" value="property1, property2"/>
</convert>

Please note that exclusion/inclusions are based on the property name not the accessor method (getter/setter)

This will ensure that DWR does not call Person.getProperty1() and Person.getProperty2(). Alternatively if you prefer to white-list rather than black-list you can do the following:

<convert converter="bean" match="com.example.Person">
  <param name="include" value="property1, property2"/>
</convert>

Good security design commonly involves white-listing rather than black-listing.

Private Members of Objects

In addition to the parameters above the 'object' converter has a force parameter that instructs DWR to use reflection modifiers to access private members of objects.

The syntax is:

<convert converter="object" match="com.example.Person">
  <param name="force" value="true"/>
</convert>

Mapping Java classes to JavaScript classes

Sometimes it is desirable to preserve the type (or sub-type) of Java objects returned from the server. This is possible by having DWR map Java classes to corresponding JavaScript classes. This is done by adding a javascript attribute to the convert element, naming the desired JavaScript class name:

<convert converter="bean" match="com.example.Person" javascript="Person"/>

Typically this feature is used with class hierarchies, so given the Person class from above we could do:

Java:

public class Employee extends Person {
  public void setEmployer(Employer emp) { ... }
  // ...
}

dwr.xml:

<convert converter="bean" match="com.example.Employee" javascript="Employee"/>

Given the above declarations we can now make use of the feature from JavaScript:

var person = ... // get an Employee from the server
person instanceof Employee // true
Remoted.addToFriends(person);

The code will result in p being assigned a JavaScript object instantiated from a generated JavaScript class 'Employee', thus the instanceof test will return the expected result. Also, when sending the object back to the server in the outlined method call, the type will be preserved so a Java Employee object will be created on the server side instead of a Person object, which would have been the normal behaviour based on addToFriends' argument type.

It is also possible to create new instances from client code in the browser:

var person1 = new Person();
var person2 = new Employee();

All of this is possible because by default DWR will add the JavaScript types for each mapping to every interface proxy script - see this page for more configuration options.

It is worth noting that DWR does not set up inheritance between generated JavaScript classes, so instanceof tests will result in:

person1 instanceof Person // true
person1 instanceof Employee // false
person2 instanceof Person // false (unexpected!)
person2 instanceof Employee // true

This is solved by setting up Employee's prototype chain in JavaScript before the first objects are created:

// Set up Employee to inherit from Person
Employee.prototype = new Person();
Employee.prototype.constructor = Employee;
...
person2 instanceof Person // true

Mapping Java classes to JavaScript classes (Lightweight)

In the examples above DWR generates code in each generated interface script to allow the mapped types to be used from your JavaScript code. In certain situations this may not be ideal (you have many mapped classes and do not want each interface script to have additional code) or required (you do not need to use the types from your JavaScript code). In these cases you can use DWR's lightweight mapping ability. First you need to configure DWR so it does not add the mapped classes to the interface scripts. This can be done with the following init-param (specified in web.xml):

  <init-param>
    <param-name>generateDtoClasses</param-name>
    <param-value></param-value>
  </init-param>
Next you need to set the $dwrClassName property on the JavaScript you are passing to your DWR remoted function:
	var employee = {
	  name: "Ralph",
	  $dwrClassName: "Employee"
	};	
	Remoted.addToFriends(employee);
Keep in mind that lightweight mapping also requires the "javascript" attribute to be set on your converter - see Mapping Java classes to JavaScript classes.

Interfaces and Abstract Classes

The class mapping feature may also be used with interfaces and abstract classes. Note though that a remoted method's argument types always have to be enabled for conversion, even when these types are non-concrete classes, otherwise DWR will not allow the data to pass through.

The generated JavaScript classes are classic JavaScript prototype definitions that are included in every generated interface file. Thus, you do not have to include any additional files to benefit from the JavaScript classes but you may want to limit the number of classes you enable for class mapping as their definitions may be downloaded multiple times (once for each interface file).

Javascript wildcard expansion

The javascript attribute of a converter will allow the * and ** wildcards. The * will map to the matched classes simple name while ** will be mapped to the fully qualified named. A few examples may help illustrate this feature:

<converter type="bean" match="model.BeanA" javascript="*" />
Resulting JS identifier: BeanA
<converter type="bean" match="model.BeanA" javascript="**" />
Resulting JS identifier: model.BeanA
<converter type="bean" match="model.BeanA" javascript="foo.bar.*" />
Resulting JS identifier: foo.bar.BeanA