Sep 05

GWT (Google web toolkit) is a great development toolkit for web applications. I’ve been following it for a white now (including two somehwat popular posts about drag and drop and about enums, back when those weren’t so popular..) and it keeps getting better and better. Recently, in version 2.1, they’ve added something called the RequestFactory, which is something nifty to replace GWT-RPC calls when those are needed for DTOs. In effect, it allows you to have most of your logic in the browser, and close to no code in the server side, especially if your application is mostly retrieving data and setting it nicely for display.

This framework does everything for you: serialization, proxy creation, remote call exposure, error handling, and more. And it even gets better in 2.4. But with all that automatic glory, something was missed, which is asymmetric accessors, i.e. writing a getter method without an accompanying setter method. And that’s what I’m writing about today.

Why would I want asymmetric accessors?

So why would we even want asymmetric accessors? Well, the answers lies in the concept of encapsulation, and calculated fields. Just like not all fields in an object are persistent (marked with @Transient), not all fields on the client side are “concrete” on the server side; some of them are calculated from different values. The easiest example for this would be the following:

class Person {
	@NotNull private String firstName;
	@NotNull private String lastName;
 
	@Transient
	public String getFullname() {
		return firstName + " " + lastName;
	}
}

As you can see, the field “fullname” is just a concatination of the first and last names. The implementation hides the contract of the object – perfect encapsulation. However, there cannot be a “setter” method for this field; while we could think of a simple implementation that splits the full name at the first whitespace, it’s not the case for a lot of calculated fields.

ServiceLayer and ServiceLayerDecorator

So who causes the problem in the long chain of the RequestFactory architecture? Essentially, you can find it in a few locations. First, somehow the AutoBean representing your proxy decides that it is different from what’s currently on the server. This happens in very few situations, but when it does, the second part comes in: it tells the ServiceLayer that these properties should be set for the server-side object. The ServiceLayer looks for the setter method, and when failing to find one, throws an exception and – boom, your application fails. I’m skipping a few mediation objects here; maybe one day I’ll write a full article on what happens behind the scenes there.

Luckily, the ServiceLayer is extensible and designed using the chain of responsibility design pattern. You are allowed to write plugins, or ServiceLayerDecorators, and these will work before GWT’s built-in code steps in. This way, for certain funcionality required, you can override GWT’s behavior. But if you’d look through Google’s documents about RequestFactory you won’t find how to use these decorators; but it’s not a tough task. All you need to do is extend the RequestFactoryServlet, and pass the decorators to the parent class when initiaised.

The solution

So the cleanest solution I’ve found so far is:

  1. Annotate: create an annotation, @CalculatedField in my case, and make it available in runtime (RetentionPolicy=RUNTIME).
  2. Decorate: create a decorator, CalculatedFieldDecorator, which overrides the setProperty method and ignores calls to it if the getter of that property is annotated with @CalculatedField.
  3. Extend: create MyRequestFactoryServlet which extends GWT’s servlet, and pass our decorator to it
  4. Wire: use our servlet in the web.xml file, and annotate our field in the class code.

The code should look something like this:

class Person {
	...
	@Transient @CalculatedField
	public String getFullname() { ... }
}
 
class CalculatedFieldDecorator extends ServiceLayerDecorator {
    public void setProperty(Object domainObject, String property, Class expectedType, Object value) {
        if (getGetter(domainObject.getClass(), property).isAnnotationPresent(CalculatedField.class)) {
            // do nothing (it's okay - the value is calculated anyway.)
        } else {
            super.setProperty(domainObject, property, expectedType, value);
        }
    }
}
 
class MyRequestFactoryServlet extends RequestFactoryServlet {
	public MyRequestFactoryServlet() {
		super(new DefaultExceptionHandler(), new CalculatedFieldDecorator());
	}
}

and there you have it! You will never see the message “Could not locate setter for property” ever again!

Conlcusion

I think that either Google overlooked an important issue, or I’m missing something important here. After tweaking my code a lot, I couldn’t get around creating the proposed code, but I’m sure Google could and should make a more elegant solution. On the other hand, I think this is a perfect case for making an API that makes it easy to do most tasks people would want, and makes it possbile to do everything else. Personally, I believe this should be a guideline all API writers should follow, and I’m glad Google chose it here.

Share
Oct 29

The classic producer-consumer pattern makes a few assumptions in order to work. In this post I’ll discuss some of these assumptions, what happens when they break, and a cool solution to deal with it.
The two assumptions I’d like to discuss are:

  1. All producers are equal – this means that all producers are limited by one, shared limit – the mediator queue between them and the consumers. This is a great assumption for most implementations: usually you are limited by the amount of work your consumers can handle and usually those are limited by the amount of processors you would physically have, therefore it doesn’t matter if the piece of work came from producer X or producer Y – either way you’d still have the same amount of processors.
  2. Once sent to the queue, a producer doesn’t care about its products – this means that there is no link between the produced work and the producer once it has been sent to the mediation queue. And why should it? Its task was to create the work, afterwards its the consumer’s job to deal with the work, and then it would be the garbage collector’s task to reclaimed the memory space that work used. If the producer kept a link to the work, it couldn’t have been reclaimed without proper notifications between the producer and the consumer – and that would be completely against the decoupling nature of the producer-consumer pattern.

So far you might be thinking “these are good, based assumptions; why should they ever break?”. Well, keep on reading then. Continue reading »

Share
Aug 08

After not touching the yielder project for a long time, I decided to go back and make the change I knew I needed but feared of doing: changing from the visitor model to the tree model of ASM.

It wasn’t even about performance anymore, as I was sure that the performance would be just as great. It was about needing to rethink the entire model again, and about being lazy.

Laziness is the end of all home-made projects, indeed.

Enough rants. I made the change, and now all the problems the previous version used to have – such as methods not necessarily working in a yield clause etc, are working.

Please, read all about it here, and get it from the Google Code project here. And obviously, let me know how it works for you, either in comments or on the issues page, here.

Thanks!

Share