Unfortunately, I’m back to developing Flex applications and mostly been focused on the communication layer between our Flex application and the Java backend. Adobe’s BlazeDS product is the easiest way to communicate between a Flex client and a Java backend. BlazeDS integrates cleanly with Spring, has annotations to expose methods as services and integrates directly with Spring security. However, like most Flex features, it has it’s quirks. Our model objects follow the Fluent Interface pattern and we make use of method chaining to remove some of the code clutter when setting multiple properties. Furthermore, our object models are interfaces since the representations may be pulled from a large variety of backend stores. Of course, this doesn’t work with the Blaze DS serialization. This post is about all the wrong ways to do this and the explanation for why it doesn’t work. I cover my solution at the end.
The (Simplified) Java Model
// net.vijedi.java.User
interface User {
String username();
}
// net.vijedi.java.HibernateUser
@Entity
class HibernateUser implements User {
@Column
private String username;
public String getUsername() {
return username;
}
public User setUsername(String name) {
username = name;
return this;
}
}
Mapping to ActionScript in all the Wrong Ways
My first attempt was to map the AS object to the interfaceUser
// net.vijedi.as.User
[RemoteObject(alias="net.vijedi.java.User")]
class User {
public var username:String;
}
Inspecting the event.result
returned in the Blaze DS callback showed that the framework had converted it to a AS User
object. However, the username property was null
. Changing the metadata to [RemoteObject(alias="net.vijedi.java.HibernateUser")]
yielded the same result. Likewise, changing [RemoteObject]
simply returned an empty ObjectProxy
.
The problem is in using the fluent interface pattern. Blaze DS requires the object to follow Java Bean schematics. This means that setters must not have a return type.
Changing the net.vijedi.java.User
interface to follow bean schematics didn’t have the desired effect. The ActionScript side showed an ObjectProxy
with the correct values set. Blaze DS sends the concrete type information as part of the return. It will still create the object, but it will not be what you want. Since AS is not a duck-typed language event.result AS User
will throw a runtime exception.
The Only Way to Do It
Changing the Java class to:
class HibernateUser implements User {
private String username;
public String getUsername() {
return username;
}
public void setUsername(String name) {
username = name;
}
}
and the ActionScript class to:
[RemoteObject(alias="net.vijedi.java.HibernateUser")]
class User {
public var username:String;
}
This actually worked. The end result is that if you would like to use Blaze DS’s mechanisms for object serialization, the best bet is to create a set of custom value objects that are used for communication. This prevents serialization failures resulting from changes to the underlying models and frees the rest of the interfaces from being tightly coupled with the front end.
One Last Note about Booleans
If you have a field namedboolean isEnabled
, most IDE’s will create the getter boolean isEnabled(){...}
. However, Blaze DS doesn’t remap it back the same way and the Actionscript side needs to be var enabled:Boolean
, without the “is.”