Flex Pasta » 2008 » May
Like many Flex/Java applications, they are started from scratch and use java 1.5 or greater. I was surprised that there were no annotations for BlazeDS to make it easier to mark up remote objects and services. Being that BlazeDS is open source, I thought it would be valuable to use annotated classes for remote objects. I created a custom BeanProxy(a class that defines what properties go from Java to actionscript, and vice versa). Note: I have submitted the code to Adobe for acceptance into the BlazeDS code base. I plan on expanding the code further, and I hope others will contribute as well. The link to the enhancement request can be found here: Please vote for the issue! Inclusion into the BlazeDS code base will help make it maintainable in the long run.
Now for a step by step guide about the annotations, and how to use them. First, I will point out that somethings I have done in the code are not ideal but are necessary to be compatible will BlazeDS which is primarily a java 1.4 app.
- Download the Jar and source: BlazeDS Annotations Jar and Source Files
- Take one of your domain classes/remote objects and implement IAnnotatedProxy and mark the class with the @FlexClass Annotation. The IAnnotatedProxy is a marker interface and its existence is simply to tell BlazeDS it has annotatations and should use the AnnotatedBeanProxy instead of the normal BeanProxy.
- Add this one liner to the servlet init of your webapp:
PropertyProxyRegistry.getRegistry().register(IAnnotatedProxy.class, new AnnotatedBeanProxy()); - Begin adding @FlexField annotations to your “getter” methods on your remote objects. As I will explain in more detail, I have broken up what the @FlexField annotation does into two parts:
- Annotations that manipulate whether a field is included in BlazeDS AMF serialization.
- @FlexField( fieldType = FlexFieldType.ReadWrite) - Default option. Acts just like domain objects do today with BlazeDS, it reads a field if and only if both a matching getter and setter exist.
- @FlexField( fieldType = FlexFieldType.Exclude) - Does not include this field in AMF serialization even though a matching getter and setter may exist. Benefits are 1) Performance, 2) Security, and 3) Unnecessary Clutter. Keep in mind though, if you have a field populated with data going from Java to Flex, when it comes back from Flex to Java, the fields you excluded will be null.
- @FlexField( fieldType = FlexFieldType.Transient) - Include this field in serialization from Java to Flex if it has a “getter” method, but it does not require a matching “setter” method. The primary benefit here is I may have a field such as a calculation that doesn’t have a “setter” because it is a calculation. Yet I want the field to be translated over to the flex front end because I will use it for display only purposes to the end user.
- Annotations that manipulate data during serialization primarily for security purposes. Note, for use of the following annotations, remote objects on both the flex and Java side MUST extend mx.rpc.remoting.JavaObject. Before using the following annotations, make sure to fully understand what they are doing.
- @FlexField( fieldType = FlexFieldType.ReadOnly) - This field is included in serialization to and from Java and Flex. However, when data is coming from Flex into Java, encoded data in the JavaObject’s key determines the value of the field. Example: An account number field with the value of 999 is passed from Java to Flex. The account number is encoded in the JavaObject’s “key” field. Now the user goes to save their account settings, so data is sent back from Flex to Java. If the account number is anything other than “999″, a (runtime) ReadOnlyException is thrown. The primary benefit here is security. I want the user to be able and see, but not edit the account number on the Flex side. There may be other fields in the domain class they can edit, but this field is off limits.
- @FlexField( fieldType = FlexFieldType.CreateOnly) - This field is included in serialization to and from Java and Flex, and is almost identical to the ReadOnly Annotation. The difference here is that, if the field has no value(is null) when it goes from Java to Flex, the field can be created on the flex side and sent back. An example here is a foreign fey field. I have a customer creating an order. The order contains a customer id field. I want to let the customer create an order with their customer id for the first time, but after that, want to make sure that data is not tampered with later.
- Annotations that manipulate whether a field is included in BlazeDS AMF serialization.
Web 2.0 and Security
With Web 2.0, application security is a big concern. Data is much more exposed to the curious eyes of an end user (especially primary and foreign keys) than in a traditional web app. My post on BlazeDS and Security goes into more detail. One of the driving forces for these annotations is for object security.
Annotations: To be Continued….
The annotations here create a starting point for use in BlazeDS. I hope the community will build on these annotations. The next goal is to tackle securing remote service methods using annotations. Feel free to post ways you would like to see annotations used with BlazeDS in the future.
A common hurdle a developer may face is dealing with exceptions in BlazeDS. When an exception is thrown in Java, how do we handle this in flex? Here is a simple and flexible approach inspired by Scott Morgan.
1. Create a Java Class that extends RuntimeException.
package com.flexpasta.exception;
public class FlexException extends RuntimeException
{
public FlexException(String message)
{
super(message);
}
}
2. Create a matching flex class called FlexException, and put the usual RemoteObject tag in their so BlazeDS will know what to look for. Also remember in actionscript, each object must be instantiated at least once, so be sure to do that somewhere with FlexException.
3. In Java, whenever there is a known exception, or some error where the end user needs to be shown a message, throw a FlexException and pass in the message the user should see in the constructor. Let’s say the user just entered an invalid password. throw new FlexException(”Wrong Password Entered, Please Try Again.”);
4. Flex receives the Exception in the form of a fault. In the fault handler, you call this method:
/**
* Parse the incoming fault for an FlexException class. If the exception class is found and it has a matching actionscript class,
* show an alert to the user with the correspoding messages. If we don't recognize the Exception type, show a generic error.
*
* @param fault
*
*/
public static function handleException(fault:Fault): void
{
var msg : String = fault.faultString;
var clazz : Class = getExceptionClass(fault);
var instance : Error = null;
if (clazz != null)
{
Alert.show(msg,'Error');
}
else
{
Alert.show('Error! Please try again. If this issue persists, contact the system administrator');
}
}
/**
*
* Return the Class corresponding to the exception by parsing the fault string. If a corresponding actionscript error class is found,
* return it. Otherwise, return null.
*
* @return
*
*/
public static function getExceptionClass(fault:Fault) : Class
{
var clazz:Class = null;
var index:int = myFault.faultString.indexOf("FlexException");
if (index != -1)
{
var cname:String = myFault.faultString.substr(0,index-1);
try
{
clazz = getDefinitionByName("com.flexpasta.FlexException") as Class;
}
catch (e:ReferenceError)
{}
}
return clazz;
}
When we see a Flex Exception, we show the message to the end user. If for some reason we have an unplanned error in Java, like NullPointerException, a message is displayed to the end user: ‘Error! Please try again. If this issue persists, contact the system administrator’. A generic message to handle all unplanned errors.
5. What if the app needs to DO something special with certain Java Exceptions? Say the user has just entered 3 password attempts, and I want to be able to handle locking their account through an exception.
Conclusion
It is pretty simple with BlazeDS to create a base exception handling system. Depending on project needs, this approach can easily be modified or enhanced. In flex, it is important to setup a strong exception handling that accounts for both planned and unplanned exceptions.