I caught one of my collegueas trying to hack a custom way of handling a complex HTML form. He was trying to use the parameter names of his form to create some sort of imperative language his constructs looked something like this:

updateAction/[obj_id]/[field_name]/[field_value]
createAction/[obj_type]/[field_name]/[field_value]
deleteAction/[obj_id]
...

After programming for a couple of hours he came to me to ask me how I would solve the composite fields puzzle using the above.

This is where the discussion took of.

I would NEVER actually do the above, IMHO the above conflicts with all OOP best practices and:

  • Plenty of solutions are availlable, every self respecting framework has a data binder...
  • Is hard to maintain
  • Is hard to extend
  • Even harder to test fully

During the discussing I made a classic 'first-speak-then-tink' mistake: I told the crowd I could build something like the above using the Springs' databinder and a flexible object model in less then two hours.
The issue kept me thinking on my way home... was Spring up for it?

But after less then one hour of not-so-hard work I solved the above:

1. The model

I created a flexible model, which allows for extension:

Model

Java by default doesn't automatically create non-existing referenced items in maps and lists I used a couple of nifty commons-collections utils to sort out that bit:

@SuppressWarnings("unchecked") // suppress conversion warning in the constructor, no objects in list yet
public FormGraph(){
// Lazy lists (commons-collections) automatically 'grow' when non existent objects are accessed
relations = ListUtils.lazyList(relations,FactoryUtils.instantiateFactory(FormGraph.class));
dateFields = MapUtils.lazyMap(dateFields, FactoryUtils.instantiateFactory(DateTime.class));
}

2. Configure Springs' ServletRequestDataBinder

When I had the model finished I configured the databinder to bind request parameters to the FormGraph object:

FormGraph bean = new FormGraph();
ServletRequestDataBinder binder = new ServletRequestDataBinder(bean,"formGraphBean");
binder.bind(request);

3. Write unit test

To see if the above worked I wrote a small unit test:

JAVA:
  1. // setup mock request
  2. MockHttpServletRequest request = new MockHttpServletRequest();
  3. // parent params
  4. request.addParameter("number", "12345");
  5. request.addParameter("type", "news");
  6. request.addParameter("textFields['title']", "title");
  7. request.addParameter("textFields['body']", "body");
  8. // relation 0
  9. request.addParameter("relations['0'].number", "456");
  10. request.addParameter("relations['0'].type", "link");
  11. request.addParameter("relations['0'].textFields['url']", "http://www.google.com");
  12. // relation 1
  13. request.addParameter("relations['1'].number", "789");
  14. request.addParameter("relations['1'].type", "link");
  15. request.addParameter("relations['1'].textFields['url']", "http://www.yahoo.com");
  16. request.addParameter("relations['1'].dateFields['created'].date", "06-07-2006");
  17. request.addParameter("relations['1'].dateFields['created'].time", "10:11:12");
  18. WizardController wc = new WizardController();
  19. try {
  20. ModelAndView mav = wc.handleRequest(request, null);
  21. System.out.println(mav.getModel().get("resultBeans"));
  22.  
  23. // TODO: actual test here
  24. } catch (Exception e) {
  25. fail("error while handling request: " + e.getMessage());
  26. }

It works like a charm, now let's see what he thinks about my solution!

4. Finished...

Well, not really... no error handling and validation yet... but enough to be used to demonstrate how Springs' binding

could be used to solve the problem without writing a custom interpreter!


2 Responses to “Complex forms & Springs’ ServletRequestDataBinder”

  1. 1 peter

    Hmm,

    after getting my colleguea to work with the code I wrote he immediately ran into a problem which is somehow caused by the binder. It seems that if a variable is present in the request multiple times the value is set using comma's to seperate the different values... Strange!! I posted the issue on the Spring forum, but no response yet...

    --

    After conducting some test the above seems to be a feature. If the source value is of type array (which is the case when multiple identical params are posted) and the target value isn't the binder tries to convert the array into the target type! If the target type is an array everything is fine!

  2. 2 Gregory Robinson

    Thanks

Leave a Reply





About

Welcome to the weblog of Peter Maas. Here you'll find various posts related to stuff I like (like my kids and espresso) and stuff I do (like developing software).

JavaOne 2008 Pictures

koffie kapot Community One Keynote boottocht IMG_4567 IMG_4686.JPG kleine libelle IMG_4571 vlieg Cable Car line IMG_4599 Scribbled Sun Logo IMG_4616.JPG IMG_6149 spidercrab IMG_4570 trap (II) javaone2008 keynote Danielle op de bruggen van Beeld en Geluid IMG_6124 tarte tatin of red unions
View more photos >

Categories



Meld u aan voor PayPal en begin direct met het accepteren van creditcardbetalingen.