001/* 002 * Copyright 2002-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.validation; 018 019import org.springframework.beans.PropertyAccessException; 020import org.springframework.context.support.DefaultMessageSourceResolvable; 021import org.springframework.util.ObjectUtils; 022import org.springframework.util.StringUtils; 023 024/** 025 * Default {@link BindingErrorProcessor} implementation. 026 * 027 * <p>Uses the "required" error code and the field name to resolve message codes 028 * for a missing field error. 029 * 030 * <p>Creates a {@code FieldError} for each {@code PropertyAccessException} 031 * given, using the {@code PropertyAccessException}'s error code ("typeMismatch", 032 * "methodInvocation") for resolving message codes. 033 * 034 * @author Alef Arendsen 035 * @author Juergen Hoeller 036 * @since 1.2 037 * @see #MISSING_FIELD_ERROR_CODE 038 * @see DataBinder#setBindingErrorProcessor 039 * @see BeanPropertyBindingResult#addError 040 * @see BeanPropertyBindingResult#resolveMessageCodes 041 * @see org.springframework.beans.PropertyAccessException#getErrorCode 042 * @see org.springframework.beans.TypeMismatchException#ERROR_CODE 043 * @see org.springframework.beans.MethodInvocationException#ERROR_CODE 044 */ 045public class DefaultBindingErrorProcessor implements BindingErrorProcessor { 046 047 /** 048 * Error code that a missing field error (i.e. a required field not 049 * found in the list of property values) will be registered with: 050 * "required". 051 */ 052 public static final String MISSING_FIELD_ERROR_CODE = "required"; 053 054 055 @Override 056 public void processMissingFieldError(String missingField, BindingResult bindingResult) { 057 // Create field error with code "required". 058 String fixedField = bindingResult.getNestedPath() + missingField; 059 String[] codes = bindingResult.resolveMessageCodes(MISSING_FIELD_ERROR_CODE, missingField); 060 Object[] arguments = getArgumentsForBindError(bindingResult.getObjectName(), fixedField); 061 FieldError error = new FieldError(bindingResult.getObjectName(), fixedField, "", true, 062 codes, arguments, "Field '" + fixedField + "' is required"); 063 bindingResult.addError(error); 064 } 065 066 @Override 067 public void processPropertyAccessException(PropertyAccessException ex, BindingResult bindingResult) { 068 // Create field error with the exceptions's code, e.g. "typeMismatch". 069 String field = ex.getPropertyName(); 070 String[] codes = bindingResult.resolveMessageCodes(ex.getErrorCode(), field); 071 Object[] arguments = getArgumentsForBindError(bindingResult.getObjectName(), field); 072 Object rejectedValue = ex.getValue(); 073 if (ObjectUtils.isArray(rejectedValue)) { 074 rejectedValue = StringUtils.arrayToCommaDelimitedString(ObjectUtils.toObjectArray(rejectedValue)); 075 } 076 FieldError error = new FieldError(bindingResult.getObjectName(), field, rejectedValue, true, 077 codes, arguments, ex.getLocalizedMessage()); 078 bindingResult.addError(error); 079 } 080 081 /** 082 * Return FieldError arguments for a binding error on the given field. 083 * Invoked for each missing required field and each type mismatch. 084 * <p>The default implementation returns a single argument indicating the field name 085 * (of type DefaultMessageSourceResolvable, with "objectName.field" and "field" as codes). 086 * @param objectName the name of the target object 087 * @param field the field that caused the binding error 088 * @return the Object array that represents the FieldError arguments 089 * @see org.springframework.validation.FieldError#getArguments 090 * @see org.springframework.context.support.DefaultMessageSourceResolvable 091 */ 092 protected Object[] getArgumentsForBindError(String objectName, String field) { 093 String[] codes = new String[] {objectName + Errors.NESTED_PATH_SEPARATOR + field, field}; 094 return new Object[] {new DefaultMessageSourceResolvable(codes, field)}; 095 } 096 097}