@PathVariable
is not meant to be validated in order to send back a readable message to the user. As principle a pathVariable should never be invalid. If a pathVariable is invalid the reason can be:
- a bug generated a bad url (an href in jsp for example). No
@Valid
is
needed and no message is needed, just fix the code;
- "the user" is manipulating the url.
Again, no
@Valid
is needed, no meaningful message to the user should
be given.
In both cases just leave an exception bubble up until it is catched by
the usual Spring ExceptionHandlers in order to generate a nice
error page or a meaningful json response indicating the error. In
order to get this result you can do some validation using custom editors.
Create a CustomerNumber
class, possibly as immutable (implementing a CharSequence
is not needed but allows you to use it basically as if it were a String
)
public class CustomerNumber implements CharSequence {
private String customerNumber;
public CustomerNumber(String customerNumber) {
this.customerNumber = customerNumber;
}
@Override
public String toString() {
return customerNumber == null ? null : customerNumber.toString();
}
@Override
public int length() {
return customerNumber.length();
}
@Override
public char charAt(int index) {
return customerNumber.charAt(index);
}
@Override
public CharSequence subSequence(int start, int end) {
return customerNumber.subSequence(start, end);
}
@Override
public boolean equals(Object obj) {
return customerNumber.equals(obj);
}
@Override
public int hashCode() {
return customerNumber.hashCode();
}
}
Create an editor implementing your validation logic (in this case no whitespaces and fixed length, just as an example)
public class CustomerNumberEditor extends PropertyEditorSupport {
@Override
public void setAsText(String text) throws IllegalArgumentException {
if (StringUtils.hasText(text) && !StringUtils.containsWhitespace(text) && text.length() == YOUR_LENGTH) {
setValue(new CustomerNumber(text));
} else {
throw new IllegalArgumentException();
// you could also subclass and throw IllegalArgumentException
// in order to manage a more detailed error message
}
}
@Override
public String getAsText() {
return ((CustomerNumber) this.getValue()).toString();
}
}
Register the editor in the Controller
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(CustomerNumber.class, new CustomerNumberEditor());
// ... other editors
}
Change the signature of your controller method accepting CustomerNumber
instead of String
(whatever your ResponseObject
is ...)
@RequestMapping(value = "/number/{customerNumber}")
@ResponseBody
public ResponseObject searchByNumber(@PathVariable("customerNumber") CustomerNumber customerNumber) {
...
}
MethodValidationPostProcessor
in yourWebMvc context
even if it's already defined in yourRoot context
. – Jeepers