|
From: Ben A. <ben...@ac...> - 2004-10-04 22:10:53
|
I'm using SimpleFormController to process a form containing a parameter that is converted to a Long value in the form backing object. The Long has a check digit and thus there are both number format exceptions as well as check digit related exceptions possible. By default such errors will cause the following messages to be displayed to the user in the errors list: Failed to convert property value of type [java.lang.String] to required type [java.lang.Long] for property 'luhn'; nested exception is java.lang.IllegalArgumentException: Cannot parse number: Unparseable number: "aString" or Property 'luhn' threw exception; nested exception is java.lang.IllegalArgumentException: Business key must be a valid Luhn identifier Neither response is suitable for display to users. I would rather replace these with my own more user-friendly message. One approach discussed at http://forum.springframework.org/viewtopic.php?t=1098 (last post by ojolly) is for the PropertyEditor to set the object to null, then detect something was actually entered in the request parameter in onBindAndValidate and then add a friendly error. That's OK, but then you lose whatever the user actually typed in as the PropertyEditor set it to null. This is unacceptable as quite often the data entered will be close to what it should have been (eg an unwanted fractional portion for an integer, a mis-typed digit for a checksum-based number, a property that is simply too long etc). I ended up writing a MyBindException which subclasses BindException and provides these two methods: public void removeError(ObjectError error) { this.errors.remove(error); } public void removeErrors(List objectErrors) { Iterator iter = objectErrors.iterator(); while (iter.hasNext()) { ObjectError objectError = (ObjectError) iter.next(); removeError(objectError); } } My controller then does this: protected void onBindAndValidate(HttpServletRequest request, Object command, BindException errors) throws Exception { Person person = (Person) command; if (errors.hasFieldErrors("luhn")) { // Cast is safe as createBinder caused MyBindException to be used MyBindException myErrors = (MyBindException) errors; errors.rejectValue("luhn", "LUHN_INVALID", "A valid Luhn is required."); } .... This works great. It consumes the unwanted, uninformative user feedback and replaces it. It also avoids needing to look at HttpServetRequest parameters. The problem is to achieve this I've needed to write MyBindException, copy nine methods to it (as the errors List is private in the BindException superclass), write a MyServletRequestDataBinder to set it up, and then override createBinder in the controller to use MyServletRequestDataBinder. It seems a lot of work, so I was hoping we could add the above two methods to BindException? Alternatively, at least making the errors List protected in BindException will save the ugly code duplication. Alternatively, if there's another way entirely of achieving this, I'd be grateful if someone would let me know. Best regards Ben |