RSS
Facebook
Twitter

Wednesday, October 10, 2007

Monday, July 16, 2007

Validation with Spring Modules Validation

So if java generics slightly disappointed me lately, what have I found cool?

I'm currently working on a web application using Spring MVC, which probably doesn't come as a big surprise, it seems to be all the rage these days. Since this is my baby, I got to call the shots as to a lot of the framework choices. When it came to looking at implementing validation, I refused to believe I'd have to go through the primitive process of looking at all the values on the request and deciding if they pass muster, with some huge if statement. Even with Spring's rather marvelous binding and validation mechanisms to take the worst of the tasks off you, it still looked like it would be a bit of a chore. Given all the cool things you can do with AOP etc I figured someone somewhere must've implemented an annotations-based validation plugin for Spring.

And they have. And there's actually a reasonable amount of information about how to set it up and get it working. The problem is that it's pretty flexible and has a lot of different options, so when you are running Java 1.5 and Spring 2.0, and actually want to use the validation in a simple, straightfoward fashion, the setup instructions get lost.

So here's my record so I don't forget in future how I did it.

As a brief summary for those who may not be familiar with Spring, or for those who need reminding (no doubt me in a few months when I've completely forgetten what I was working on), Spring provides a Validator interface that you can use to easily plug validation into your application. In the context of web applications, you create your various Validators and in your application context XML file you tell your Controllers to use those validators on form submission (for example).

Spring Modules validation provides a bunch of generic validation out of the box for all the tedious, standard stuff - length validation, mandatory fields, valid e-mail addresses etc (details here). And you can plug this straight into your application by using annotations. How? Easy.

This is my outline application context file:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns=" http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance "
xmlns:vld="http://www.springmodules.org/validation/bean/validator "
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springmodules.org/validation/bean/validator http://www.springmodules.org/validation/bean/validator.xsd">

<vld:annotation-based-validator id="validator" />

<!-- Load messages -->
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames" value="messages,errors" />
</bean>

<!-- Bean initialisation for validation. You can put these explicitly into your controllers or set to autowire by name or type -->
<bean id="messageCodesResolver"
class="org.springmodules.validation.bean.converter.ModelAwareMessageCodesResolver" />

</beans>

Really all you're interested in is the addition of the validation namespace and schema at the top of the file, and the <vld:annotation-based-validator id="validator" /> line which is your actual validator. The other sections are a message source so your error codes can have meaningful messages and a MessageCodeResolver to make use of these.

Eclipse does seem to moan about the way the springmodules schema is referenced, but when you actually start Tomcat up it seems happy enough.

I've chosen to give the validator the ID validator because I turned autowire by name on so that all my controllers picked up this validation by default. Note: autowire can be a little bit dangerous and I've actually turned it off now because I had a validator bean and a validators list in the context file and my poor SimpleFormController controllers were getting a bit confused over which one to use (in truth, the single validator was overwriting the list, which was not what I was after at all).

Anyway. Now what? We have a validator and we've probably wired it into the relevant controllers, either by autowiring them or poking it specifically into our controllers like this:

<bean id="somePersonController"
class="com.mechanitis.examples.validation.controller.MyPersonController">
<property name="commandClass"
value="com.mechanitis.examples.validation.command.PersonCommand" />
<property name="formView" value="person" />
<property name="successView" value="success" />
<property name="validator" ref="validator"/>
</bean>

Next step is to add some validation rules. The documentation will show you how to do this using an XML file, which you're perfectly welcome to do. However what I wanted to show is how to use annotations on your command object to declare your validation. So here you are:


import org.springmodules.validation.bean.conf.loader.annotation.handler.CascadeValidation;
import org.springmodules.validation.bean.conf.loader.annotation.handler.Email;
import org.springmodules.validation.bean.conf.loader.annotation.handler.Length;
import org.springmodules.validation.bean.conf.loader.annotation.handler.Min;
import org.springmodules.validation.bean.conf.loader.annotation.handler.NotNull;

public class PersonCommand {
private static final int NAME_MAX_LENGTH = 50;

@NotNull
@Length(min = 1, max = NAME_MAX_LENGTH)
private String name;

@Min(value=1)
private Long age;

@Email
private String eMail;

@CascadeValidation
private RelationshipCommand relationship = new RelationshipCommand();

private String action;

//insert getters and setters etc

}

Note that @CascadeValidation tells the validator to run validation on the enclosed secondary Command.

This is just a simple example obviously. But hopefully you can see that now you've got the validator set up correctly in your application context file, all you need to cover 90% of your validation needs is to tag the relevant fields with the type of validation you want. If you want to get really clever, the validator supports Valang which allows you to write simple rules. For example, if I only want to validate the name when I'm saving the person rather than passing the command around for some other purpose, I might change the annotations on the name field:


@NotNull(applyIf="action EQUALS 'savePerson'")
@Length(min = 1, max = NAME_MAX_LENGTH, applyIf="action EQUALS 'savePerson'")
private String name;

That's the basics. Before I let you go off and play though, a word about error messages. As usual with Spring validators, you can specify pretty messages to be displayed to the user when things go wrong. In my application context file above you should see that I've specified a properties file called errors. In this file you can map your error codes to the message to display. When using the spring modules validation I found the error codes generated were like the ones below so you might have an errors.properties file that looks like this:


# *** Errors for the Person screens
PersonCommand.age[min]=An age should be entered
PersonCommand.name[length]=Person name should be between 1 and 50 characters
# etc etc

# *** General errors
not.null=This field cannot be empty


Go play.

Saturday, July 7, 2007

Java Specifics

When I first started playing with Java 1.5, I thought generics were the best thing since sliced bread. No more untidy casting, lovely type-safe Collections, and when combined with the new for loop, a lot of the tedious tasks associated with Collections became easier and, most importantly, aesthetically pleasing.



Consider the old code:


List list = new ArrayList();
list.add(new Integer(1));
Integer integer = (Integer)list.get(0);

for (Iterator i = list.iterator(); i.hasNext(); ) {
Integer number = (Integer)i.next();
number.intValue();
}


And the new:

List<Integer> list = new ArrayList<Integer>();
list.add(new Integer(2));
Integer integer = list.get(0);

for (Integer number : list) {
number.intValue();
}


See? Much prettier. OK so it's a silly little example but when you apply it to all the places you use things like Collections it does make life a lot easier, especially when you consider that now you *know* what's in that List that comes back from some method that you're not familiar with.



Nearly two years on from the first time I started using them, I run into an issue - they're not generic at all. They're specific. The point about generics as far as I can figure out is type-safety - they remove the need to cast everything everywhere. Which is great, until you actually want a little flexibility in your types. So, you can have the code above which adds and retrieves Integers from a list, knowing that it's perfectly fine to get objects from that list and treat them as Integers because that's exactly what they are. But what you can't do is assign a List of some subtype to a List of one if its supertypes:


public List<Integer> getIntegers() {
List<Integer> integers = new ArrayList<Integer>();
integers.add(new Integer(1));
return integers;
}

...

public void assignList() {
List<Number> numbers = getIntegers(); //compiler error - Type mismatch
//or
numbers = new ArrayList<Integer>(); //compiler error - Type mismatch
}


OK fine, it's a bit confusing but it makes sense if you think about it. A good example is provided in this article, which explains that if you're expecting a Collection of Numbers, you might expect to be able to add a Float to it, but if lurking under the covers you've assigned a List of Integers to it, it is incorrect to add a Float to it.



So what about wildcards? Aren't they supposed to overcome this issue? Well, sort of. Wildcards in generics means you can do the following:


List<? extends Number> numbers = getIntegers();
//or
numbers = new ArrayList<Integer>();


and this will not give a compiler error. But then you can't do:


List<? extends Number> numbers = new ArrayList<Integer>();
numbers.addAll(new ArrayList<Integer>()); //compiler error
numbers.add(new Integer(1)); //compiler error


So you can use a wildcarded Collection to represent that you know that Collection is going to be some Collection that contains something that is a subclass of Number (for example), but not to say that the Collection can contain any mix of items that are a sublasses of number.



OK... what do I need to remember to prevent confusion in future?



Well, looks like we use:

List<Number> numbers = new ArrayList<Number>();
numbers.add(new Integer(1));
numbers.add(new Double(1));

if you want your collection to contain a mix of items that are subclasses of your specified generic type. But you might have to use something like addAll to insert the contents of some other List into it, as you can't assign Lists of subclasses to it.



If you want to assign Lists that have a generic type that's a subclass, then you want to use wildcards:

List<? extends Number> numbers = getIntegers();
//or
numbers = new ArrayList<Integer>();


So, easy then. No idea what I got so confused about.

Monday, April 23, 2007

Excuses excuses.

Isn't a shame that actual day-to-day work always seems to get in the way of progress?  How you're always too busy fire-fighting to actually perform the critical thing that might actually improve affairs.

All this is basically a setup for a roundabout excuse for why this blog has been neglected so shortly after it was begun.  I was a bit too busy doing the day job.

Still, people like Joel and Scott manage regular pronouncements and I'm sure they're much busier than I!

Thursday, March 22, 2007

Agile Infection Growing

This is a bloody good idea. It builds upon my own Virgoen tendancies to write lists and tick things off, but what the list model lacks is the "in progress" state. Plus occasionally my lists get confused. See today's notebook page:
Thursday

    Fix bugs in Test Director
    Merge fixes up
    Do build
    Merge down
    Read terms of contract
    E-mail solicitor
    Go to Robert Dyas
    Order DAB Radio
    Finish business analysis docs
    Carry on with QCon note consolidation

How do I know which ones I've started? I could do with a couple of boards at least as well to separate the personal from the business.

Also note that I took something away from my Time Management course, attended when I was a mere graduate at a large manufacturing organisation: make a new list for each day, discarding your completed items and moving forward the incomplete ones (it also mentions to discard "low priority" items that haven't been done over a week or two under the theory that you'll never do it if you haven't by then).  This is great for keeping a nice clean list of achievable goals for the day, but a bit rubbish at giving any positive feedback - no matter how much you get done, every day there's yet more to do, and lack of visibility on what you have actually achieved. The example story wall in the link above is great for a sense of acheivement - yes there's still things to be done but look how much has been achieved in comparison!

However, I am going to make the common criticism of cards: one of their major advantages, their "physicality"1, is also the disadvantage - whilst I can take my little notebook round with me, I can't lug a story wall between work and home. And although some of those things are personal tasks, they need to be done at work (e.g. e-mailing because I haven't got my broadband at home yet) or between work and home.

Mind you, I actually have 3 pieces of paper containing lists of things to do / buy / check / clean with regards to my new flat, because of my inability to actually carry the notebook with me.  Or the same one at least.

I think this means two more items to be added to the "To Buy" list: a magnetic whiteboard and some story cards. I like whiteboards because you can even scribble stuff behind / around the cards.

EDIT: Bah, someone else already beat me to it.


1 This is an extract from James Shore's section on Stories:
Write stories on index cards.

This isn't the result of some strange Ludditian urge on the part of XP's creators—it's a deliberate choice based on the strengths of the medium. You see, physical cards have one feature that no conglomeration of pixels has: you can pick them up and move them around. They're tactile. This gives them power.

QCon: Blogger's Summary

I might be too late in writing my own thoughts on QCon, but a bunch of other people have done a pretty good job.

Wednesday, March 21, 2007

Certifiction

From  today:
Certifiction (n.) : a professional endorsement which states only that the holder had the money to pay for the exam.
...which reminded me of this debate, particularly the first comment.

Tuesday, March 20, 2007

QCon: TODO list inspired by the conference

Continuing the Agile froth...

...there are a number of points in this interview with Paul Oldfield which are interesting to consider when thinking about "doing Agile right".  It seems to be compatible with my "people over process" view - I'm not stating that having good people negates the need for any form of process or discipline, I have seen that this is simply not the case.  I do however think that agile techniques in particular rely heavily upon the "right" people / team, for some nebulous definition of  "right".

Monday, March 19, 2007

QCon: Initial thoughts

Things I took out of QCon:

  • I want to play with Ajax.  Maybe I've "grown out" of front end development but that doesn't prevent it from being (potentially) extremely cool
  • Selenium looks like a good place to start for automated website testing
  • It can take up to 7 years to move away from a legacy architecture.  Depressing, but at least it shows it can be done and it's worth the effort
  • I'm going to become a certified Scrum Master Mistress.  I believe Agile in some form or other is the most efficient way to run software development, but there are a LOT of lessons to learn in order to get it right.  And number one lesson is you need the right team.

QCon London

Last week saw the first QCon London conference, an event "designed with the technical depth and enterprise focus of interest to technical team leads, architects, and project managers".

The conference consisted of two days of tutorials followed by three days of talks covering technologies, vendor products, and processes. In addition there were numerous "networking" opportunities with plenty of break times to both absorb information and meet other people, plus evening events.

The conference was both comprehensive and absorbing, and I'm hoping to take the next few days to filter through the notes I have taken and present a more succinct version here. Whether it will be of use to anyone other than myself remains to be seen...