Can't get any output from the <spring:hasBindErrors> taglib
I'm writing a Spring 3 MVC based web app, using JSPs for my view layer. I'm struggling on a particular area where I'm trying to report BindingResult errors for a particular Model object in a JSP. This is probably best explained with the appropriate code:
This is my Spring Controller method:
@RequestMapping(value = "/**", method = RequestMethod.GET)
public ModelAndView get(@ModelAttribute("xApiRequest") @Valid final XAPIRequest xApiRequest,
final BindingResult xapiBindingResult,
final HttpServletResponse response,
Model model) throws EntityNotFoundException {
String viewName = "/WEB-INF/views/get-single-entity.jsp";
/*
* Create a MAV passing in the original Model object which contains:
* 1: The 'xApiRequest' @ModelAttribute object.
* 2: The BindingResult for the 'xApiRequest' object.
*/
final ModelAndView mav = new ModelAndView(viewName, model.asMap());
final XAPIResponse<Resource> xApiResponse = buildXAPIResponse(false, 200, xApiRequest, null);
response.setStatus(200);
mav.addObject("xApiResponse", xApiResponse);
return mav;
}
When I execute this method I can see the following:
- The xApiRequest object is created correctly from the HttpServletRequest (I have a separate method which does this)
- The JSR-303 validation, caused by the @Valid annotation, has taken place and has identified 2 validation errors, these are represented as BindingResult objects as I would expect.
- The BindingResult objects are present in the Model method parameter.
- The xApiRequest and BindingResult objects are successfully transferred from the Model method parameter in to the ModelAndView object which is returned from the method.
And I can confirm that the content of the BindingResult does appear to correctly identify the xApiRequest object as the source of the validation errors:
{xApiRequest=com.stretchr.xapi.entity.request.XAPIRequest@1e28608, org.springframework.validation.BindingResult.xApiRequest=org.springframework.validation.BeanPropertyBindingResult: 2 errors
Field error in object 'xApiRequest' on field 'userId': rejected value [null]; codes [NotEmpty.xApiRequest.userId,NotEmpty.userId,NotEmpty.java.lang.String,NotEmpty]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [xApiRequest.userId,userId]; arguments []; default message [userId]]; default message [may not be empty]
Field error in object 'xApiRequest' on field 'projectId': rejected value [null]; codes [NotEmpty.xApiRequest.projectId,NotEmpty.projectId,NotEmpty.java.lang.String,NotEmpty]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [xApiRequest.projectId,projectId]; arguments []; default message [projectId]]; default message [may not be empty]}
And the JSP looks like this:
<%@ page contentType="application/json; charset=UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib prefix="json" uri="http://www.atg.com/taglibs/json" %>
<%@ page session="false" %>
<spring:hasBindErrors name="xApiRequest">
</spring:hasBindErrors>
<c:if test="${errors}">
<json:object name="exceptions">
<json:property name="exceptionCount" value="${errors.errorCount}" />
<json:property name="globalExceptionCount开发者_如何学运维" value="${errors.globalErrorCount}" />
<c:forEach var="error" items="${errors.allErrors}" varStatus="index">
<json:property name="${index}" value="${error.defaultMessage}" />
</c:forEach>
</json:object>
</c:if>
No matter what I do I can't seem to get the call to to recognise that the xApiRequest model object has binding errors, hence the JSP output does not contain the exceptions object containing details of the errors:
{
w: false
s: 200
c: ""
r: {
o ~path: ""
}
}
Can anyone see what I'm doing wrong here? Failing that is there any way I can debug what's going on during the JSP processing? I'm keen to debug the Spring taglib but am not quite sure how to make the link between the taglib and the associated bit of code.
Hope I've provided enough information here but if any more is required then don't hesitate to ask.
Many thanks,
Edd
The errors
variable is exposed only inside the <spring:hasBindErrors>
tags, so that you should do something like this (note that it also replaces <c:if>
):
<spring:hasBindErrors name="xApiRequest">
<json:object name="exceptions">
<json:property name="exceptionCount" value="${errors.errorCount}" />
<json:property name="globalExceptionCount" value="${errors.globalErrorCount}" />
<c:forEach var="error" items="${errors.allErrors}" varStatus="index">
<json:property name="${index}" value="${error.defaultMessage}" />
</c:forEach>
</json:object>
</spring:hasBindErrors>
How embarassing, after trying to debug the BindErrorsTag class I realised it wasn't being invoked at all. This discovery led me to realise that I hadn't included Spring taglib namespace declaration in the JSP, including this solved the problem.
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
Cursing myself for missing this now very obvious error and somewhat confused as to why the JSP (and my IDE) didn't complain about the missing taglib declaration. I thought a missing taglib declaration usually caused a RuntimeException upon execution of the tag but it seems this is not so (I wish it was as it would have saved me a good couple of hours of debugging!)
Anyway, problem solved.
@axtavt - Thanks for the help!
Oh my God! I had the same problem, thanks so much for answering your own question.
In my case - hopefully helps someone else out there - A simple JSP, calls a method such as :
@RequestMapping(method = RequestMethod.GET)
protected Object loadRegistrationForm(HttpSession session, Model model) {
This JSP returned has a form which can be submitted and gets to a Server POST method, so I had the following to capture the errors returned from the post of the form:
<spring:hasBindErrors name="customerAccountFormObj">
<div class="alert alert-block pull-right alertmessage alert-warning alert-dismissible" role="alert" id="errorMsgHdr">
<button type='button' class='close' data-dismiss='alert' aria-label='Close'><span aria-hidden='true'>×</span></button>
<form:errors path="*" cssClass="errorList" element="div"/>
</div>
</spring:hasBindErrors>
Basically a bootstrap alert message displays the errors when there are binderrors, guess what happens on GET call ? I get an empty alert box... after 12 hours of banging my head, I stumbled on your question, added
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
Voila! everything's clean, no empty alert box, i.e., no errors on GET call. This has to be a bug in JSP/Spring. I use Spring mvc 3.0.3.RELEASE if it helps anyone.
精彩评论