I'm guessing that global errors are another name for ObjectErrors
since getGlobalError() returns an ObjectError.
Actually a "global error" is any ObjectError
that is not an instance of a FieldError
see source of getGlobalErrors()
What would I be missing if I only logged FieldErrors?
Any ObjectError
s that code registered as a "global error" e.g. by calling BindingResult.reject(errorCode, errorArgs, defaultMessage)
.
See also the javadoc for rejectValue(field, errorCode, errorArgs, defaultMessage)
. Typically errors are registered against fields of the validated/bound object (e.g. the model value whose attribute matches the modelAttribute
tag of the Spring form tag) as opposed to the object itself.
Following are a couple of ways to create global errors:
Assuming it's the root form object and not a nested object that's being validated via a Spring Validator
implementation, you could add a "global error" (in the context of the specified bound root object) by passing null as the field name parameter of rejectValue
. If the object being validated is a nested object, however, a FieldError
would be registered against the nested object field. So it matters what is the nestedPath
("nested object graph") property of the target Errors
object with respect to whether a general ObjectError
or specific FieldError
is added.
Via a JSR 303 constraint annotation applied at the class level. See example in which a model object is checked for pre-existence in a datastore.
Here's an example to reference the global vs the field level errors:
public class OverflowErrorsTag extends HtmlEscapingAwareTag {
public static final String OVERFLOW_ERRORS_VARIABLE_NAME = "overflowErrors";
public static final String GLOBAL_ERRORS_VARIABLE_NAME = "globalErrors";
private String name;
/**
* Set the name of the bean that this tag should check.
*/
public void setName(String name) {
this.name = name;
}
/**
* Return the name of the bean that this tag checks.
*/
public String getName() {
return this.name;
}
@Override
protected final int doStartTagInternal() throws ServletException, JspException {
Errors errors = getRequestContext().getErrors(this.name, isHtmlEscape());
Set<FieldError> subsequentErrors = Sets.newTreeSet((fe1, fe2) -> fe1.getField().compareTo(fe2.getField()));
Set<ObjectError> globalErrors = new HashSet<>();
if (errors != null) {
Set<String> firstErrorFields = new HashSet<>();
for (FieldError fieldError : errors.getFieldErrors()) {
if (firstErrorFields.contains(fieldError.getField())) {
subsequentErrors.add(fieldError);
} else {
firstErrorFields.add(fieldError.getField());
}
}
for (ObjectError objectError : errors.getGlobalErrors()) {
globalErrors.add(objectError);
}
}
if (subsequentErrors.isEmpty() && globalErrors.isEmpty()) {
return SKIP_BODY;
} else {
this.pageContext.setAttribute(OVERFLOW_ERRORS_VARIABLE_NAME, subsequentErrors, PageContext.REQUEST_SCOPE);
this.pageContext.setAttribute(GLOBAL_ERRORS_VARIABLE_NAME, globalErrors, PageContext.REQUEST_SCOPE);
return EVAL_BODY_INCLUDE;
}
}
@Override
public int doEndTag() {
this.pageContext.removeAttribute(OVERFLOW_ERRORS_VARIABLE_NAME, PageContext.REQUEST_SCOPE);
this.pageContext.removeAttribute(GLOBAL_ERRORS_VARIABLE_NAME, PageContext.REQUEST_SCOPE);
return EVAL_PAGE;
}
}
Then to display this tag containing both global and field errors in the view:
<spring-ext:overflowErrors name="newModelObject">
<div class="row">
<div class="large-12 columns">
<div class="alert panel">
<c:if test="${overflowErrors.size()>0}">
<p>There are multiple errors with your entry.</p>
<c:forEach var="error" items="${overflowErrors}">
${fn:toUpperCase(fn:substring(error.field, 0, 1))}${fn:toLowerCase(
fn:substring(error.field, 1,fn:length(error.field)))}:
<b><spring:message message="${error}" /></b>
<br/>
</c:forEach>
</c:if>
<c:forEach var="error" items="${globalErrors}">
<b><spring:message message="${error}" /></b>
<br/>
</c:forEach>
</div>
</div>
</div>
</spring-ext:overflowErrors>