04.29.09

Simple forms with Spring MVC 2.5

Posted in General at 2:32 pm by tom

Having used the Spring MVC 2.5 webframework for a while now, I felt the urge to blog about some of the experiences I had with it. Especially about the part concerning forms, validation, binding and property editors. That’s the part that was usually provided to you by the SimpleFormController (in the ‘old’ Spring MVC). But now, in Spring MVC 2.5, where do you start? You don’t have a base class anymore that tells you what methods you can override. Instead you have a bunch of annotations and a lot of magic.

Just to clarify, I love Spring MVC 2.5. It provides much more freedom and reduces the amount of controller classes you need to write, compared to previous versions of the framework.  But you need to follow some best practices to avoid making a mess of your controller classes.

Return types

With your first glance at Spring MVC 2.5 you have probably noticed that controller methods don’t have to return a ModelAndView anymore. Instead, controllers are allowed to return nothing (void), a String representing a view, or just a model. This creates a lot of freedom, but in my opinion can also cause some inconsistency and unclarity. By convention, if your controller does not explicitly return a view, the view name is defined by converting the mapped URL into a view name. This will save you some code, but you have to remember this convention to know what’s going on. 

You should be careful not to mix the return types of all your controller methods. I suggest picking a return type and sticking with it. In my case I picked the old fashioned ModelAndView since it can contain both a view and a model, which works in all cases. This makes your controller methods consistent and makes it more clear what to expect from those methods.

Forms & binding

To create a very basic form you basically only need to handle a request to view the form and to submit the form. Let’s say we have the following class:

public class User {

     private String name;

     public String getName() {

        return name;

   

    public void setName(String name) {

        this.name = name;

    }

}

Instances of this class will get manipulated by the form controller we will create. The SimpleFormController used to call an instance of this class the “form backing object”. Let’s keep calling it this way. Implementing this very basic form in Spring MVC 2.5 would look like this:

@Controller

@RequestMapping(“/userForm.html”)

public class UserFormController {

    @RequestMapping(RequestMethod.GET)

    public ModelAndView show() {

        return new ModelAndView(“userForm”, “user”, new User());

    }

    @RequestMapping(RequestMethod.POST)

    public ModelAndView submit(User user) {

        // Do something with the submitted User

        return new ModelAndView(new RedirectView(“/userForm.html”));

    }

}

Notice that you don’t need to specify your command class. Instead, you only have to specify the class as an argument in your submit method and request binding will automagically occur.

Custom form backing object

In a lot of cases you are going to want to create and initialize the form backing object manually. In the previous example a new instance of User is automatically created when the submit occurs. With SimpleFormController creating your own form backing object can be done by overriding the formBackingObject() method. In Spring MVC 2.5, you can achieve the same behavior by specifying the @ModelAttribute annotation on the method responsible for creating that object.

@ModelAttribute(“user”)

public User formBackingObject() {

    return new User();

}

This method can also specify all kinds of arguments just like a normal controller handler method. So you could for example do the following:

@ModelAttribute(“user”)

public User formBackingObject(Long id) {

    if (id != null) {

        return userDao.findById(id);

    }

    return new User();

}

This makes it possible to use the same form controller for both adding and editing existing instances of the User object. Having a @ModelAttribute annotated method in your controller class basically tells Spring MVC to include whatever is returned by that method to every request handled within that controller class.

To make sure your submit method uses the same instance, you have to annotate its argument with @ModelAttribute as well.

@RequestMapping(method = RequestMethod.POST)

public ModelAndView submit(@ModelAttribute(“user”) User user) {

    // Do something with the submitted User

    return new ModelAndView(new RedirectView(“/userForm.html”));

}

When a submit request comes in, first our formBackingObject() method is called. Second, request binding occurs on this object. And finally this object is passed to the submit() method. So the object passed to submit() is the same instance as the one you created manually inside the formBackingObject() method.

Handling bind errors

By default, Spring MVC 2.5 throws an exception when any errors occur during request binding. You usually don’t want that. Instead you want to handle those errors yourself by presenting these errors to the user.

To do this, you have to define a BindingResult argument in the submit() method. This argument has to be right after the object on which request parameters are bound to.

public ModelAndView submit(@ModelAttribute(“user”) User user, BindingResult bindingResult)

For the exceptional case that you are binding to multiple objects, you should specify a BindingResult for each one of them like this:

public ModelAndView submit(User user, BindingResult userBindingResult, Credentials credentials, BindingResult credentialsBindingResult)

So now no exception is thrown, instead a BindingResult is passed to your submit method when errors occur. Now you can decide what to do. In most cases you only want to avoid that the submit performs any action and return to the form view that can display the errors to the user. A simple if statement can do the trick.

@RequestMapping(method = RequestMethod.POST)

public ModelAndView submit(@ModelAttribute(“user”) User user, BindingResult bindingResult) {

    if (bindingResult.hasErrors()) {

        return new ModelAndView(“formView”);

    }

    // Do something with the submitted User

    return new ModelAndView(new RedirectView(“/userForm.html”));

}

To display the errors in your JSP view (in this case called “formView”) you can simply use the Spring form taglib like you did using the old Spring MVC.

Validation

With SimpleFormController the only thing you needed to do for validation is write your own Validator class and inject it into the SimpleFormController bean. With Spring MVC 2.5 you can still use that same Validator class and inject i tinto your controller, but now you have to call it manually.

@RequestMapping(method = RequestMethod.POST)

public ModelAndView submit(@ModelAttribute(“user”) User user, BindingResult bindingResult) {

    userValidator.validate(user, bindingResult);

    if (bindingResult.hasErrors()) {

        return new ModelAndView(“formView”);

    }

    // Do something with the submitted User

    return new ModelAndView(new RedirectView(“/userForm.html”));

}

You pass your validator the same BindingResult that holds the binding errors. The validator should register any errors on this object as well.

Property editors

Finally, I want to tell you how property editors work in Spring MVC 2.5. Property editors are used by the request binder to help converting String values to other types (like a String to a Date or to a User instance). Actually, nothing is changed here except you have to specify the @InitBinder annotation instead of overriding the initBinder() method on SimpleFormController.

@InitBinder

public void initBinder(WebDataBinder binder) {

    binder.registerCustomEditor(new CustomDateEditor(“dd/MM/yyyy”, true));

    // Register any property editor you want

}

The property editors you register here are used for all binding operations performed within the same controller class.

Conclusion

Spring MVC 2.5 provides an elegant approach to handle form related requests, but you just have to know how exactly.

I hope you found this information useful. Please leave a comment in case you have questions about this topic, or want to share your experiences with Spring MVC.

08.14.07

Strange GWT compiler error

Posted in General at 11:54 am by tom

I am currently working in a project that uses GWT as the frontend technology. Recently we ran across a small problem. The GWT compiler gave the following error:

[WARNING] Not all subtypes of the automatically serializable type ‘xxx.yyy.ZzzDto’ are themselves automatically serializable

You would expect that all subtypes of a serializable class should automatically be serializable as well, but in this error you can see that is not the case. After some research we found that this is in fact true. Subtypes of a serializable type are always serializable with 2 exceptions:

A subtype has a non-serializable field

class A implements IsSerializable {}class B extends A {Object obj;}interface MyService extends RemoteService {A getA();}You can see here that class B does extend a class that is serializable, but contains a type that is not serializable.

A subtype is abstract and has no concrete implementations

class A implements IsSerializable {}abstract class B extends A {}interface MyService extends RemoteService {A getA();}

Here the problem is that class B is defined as abstract, but no other class is extending from B, so class B itself is not instantiateable and therefore not serializable.

This problem was a real pain for a short while because we couldn’t find what could be wrong. I hope this helps other people when they encounter this error.

03.08.07

HA JDBC – High Availability JDBC

Posted in General at 2:07 pm by tom

Some time ago I worked on a project which was in need of a way to cluster databases. For those of you who don’t exactly know what database clustering is: database clustering is a way to have multiple databases work together to act like a single database. A cluster of databases typically has the following benefits:

  • A cluster has a query throughput that is much higher than just a single database.
  • A database in the cluster can fail without losing access to the data.

The result is that you now have access to a ‘database’ that is never down and can handle a lot more queries than a single database could. We didn’t care much about the higher query throughput but were very interested in a database that would always be available.

After some research I found out that there were a lot of products available to accomplish this.

We decided to use HA-JDBC (= High Availability Java DataBase Connectivity), an open source Java framework that offers database clustering. In this blog entry, I will tell you about my experiences with this relatively unknown framework, and hopefully share experiences with people who also use it. But first, I will try to explain how this framework does its job.

HOW HA-JDBC WORKS

Normally when you connect to a database, you use a JDBC connection. HA-JDBC wraps one or more connections and acts like a proxy in your javacode. This means that your javacode interacts with the proxy and is transparently communicating with multiple databases.

In order for HA-JDBC to know which connections to proxy, it needs an XML configuration file. This file defines how the cluster is configured. It defines the information needed to connect to the databases, but also the behaviour of the cluster itself.Below you can read about the experiences I’ve had with a few different aspects of HA-JDBC.

SYNCHRONIZATION

One aspect of HA-JDBC is synchronization. Synchronization in HA-JDBC is the process of making an out-of-date database up-to-date again by comparing its data with other databases in the cluster. A database can get out-of-date when it gets turned off for some reason. It could have died on its own or someone could have turned it off on purpose, but in any case: it needs synchronization to have its data up-to-date again. When a database goes down, users of the application will not notice. They can continue using the application like nothing is going on because other databases of the cluster are still available.

When a database is down, it will rapidly get out-of-date because it will not process any updates anymore. When the database is started again, HA-JDBC will pick this up and executes a synchronization strategy that is configured in the XML configuration file. The downside to this is that the built-in strategies of HA-JDBC are not very efficient. These are the ones packaged with HA-JDBC:

  • FullSynchronizationStrategy: Deletes the content of all tables of the database that is being updated and fills them again with data from a different (up-to-date) database in the cluster.
  • DifferentialSynchronizationStrategy: Compares all rows of the out-of-date database with a different (up-to-date) database in the cluster to find out which rows need to be updated, inserted or deleted.
  • PassiveSynchronizationStrategy: There also is a strategy that assumes no updates have taken place during the down-time and is therefore doing nothing.

A nice thing about HA-JDBC is that you can implement your own synchronization strategy. Since the above mentioned strategies will take hours to complete on large tables we decided to write a strategy ourselves. This strategy requires tables to have a timestamp for versioning, does not support deletes but turned out to be a lot faster than the built-in strategies of HA-JDBC.

 

 

ID GENERATION

When using a single database you can let the database itself generate IDs for records you insert. When using multiple databases with HA-JDBC you can still do that, but there is no guarantee that all databases in the cluster will generate the same ID. When a different ID is generated in each database, this will leave your cluster in an invalid state because now all the databases in this cluster contain different data.

Of course there is a solution to this problem but this isn’t pretty. When using an ORM tool like Hibernate, you can specify a generator for the ID field. By default Hibernate makes the database responsible for generating IDs which is not what we want. When using HA-JDBC you should use one of the following generators:

  • UUID-generator
  • HiLo-generator.

These two generators both don’t depend on an individual database, which is just what we need, but they do not produce normal IDs. For example the UUID generator generates IDs like ‘4028828d-0dc7f2a2-010d-c7f2a4d3-0013’. This value is based on the current timestamp and the IP address of the machine the application is on. The HiLo generator generates normal numbers but they don’t increase like you’re used to. It is possible that the first number it generates is 432 and the next one is 33200, which you wouldn’t expect from IDs.

NON-INTRUSIVE?

When I started using HA-JDBC, I expected it to be non-intrusive to our project. Because the only thing we needed was to change our JDBC driver and write a simple XML configuration file for it. But as you have read in this blog entry, you first of all need to write your own strategy for synchronization, and second of all, you probably have to switch to UUIDs. This requires a lot of refactoring all over your code because you are now switching from Long typed IDs to String typed IDs. So in fact it does influence your project more than you would expect.

CONCLUSION

In conclusion, HA-JDBC is very easy to set up and has well written documentation on its website. It performs quite well, especially when writing a customized strategy for synchronization. Since it delegates calls to underlying JDBC drivers directly, it is fast and has full JDBC support. You also don’t need anything else then just your database servers and your application servers. But there are a few issues with HA-JDBC that are a bit annoying, you will probably end up with having UUIDs for records in your database and having to write your own synchronization strategy.

I was wondering if there were any other people that have some experience with this database clustering approach and would like to share their experiences. So if you have any experience with HA-JDBC, don’t hesitate to leave a comment!