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.Assert; 022import org.springframework.util.ObjectUtils; 023import org.springframework.util.StringUtils; 024 025/** 026 * Default {@link BindingErrorProcessor} implementation. 027 * 028 * <p>Uses the "required" error code and the field name to resolve message codes 029 * for a missing field error. 030 * 031 * <p>Creates a {@code FieldError} for each {@code PropertyAccessException} 032 * given, using the {@code PropertyAccessException}'s error code ("typeMismatch", 033 * "methodInvocation") for resolving message codes. 034 * 035 * @author Alef Arendsen 036 * @author Juergen Hoeller 037 * @since 1.2 038 * @see #MISSING_FIELD_ERROR_CODE 039 * @see DataBinder#setBindingErrorProcessor 040 * @see BeanPropertyBindingResult#addError 041 * @see BeanPropertyBindingResult#resolveMessageCodes 042 * @see org.springframework.beans.PropertyAccessException#getErrorCode 043 * @see org.springframework.beans.TypeMismatchException#ERROR_CODE 044 * @see org.springframework.beans.MethodInvocationException#ERROR_CODE 045 */ 046public class DefaultBindingErrorProcessor implements BindingErrorProcessor { 047 048 /** 049 * Error code that a missing field error (i.e. a required field not 050 * found in the list of property values) will be registered with: 051 * "required". 052 */ 053 public static final String MISSING_FIELD_ERROR_CODE = "required"; 054 055 056 @Override 057 public void processMissingFieldError(String missingField, BindingResult bindingResult) { 058 // Create field error with code "required". 059 String fixedField = bindingResult.getNestedPath() + missingField; 060 String[] codes = bindingResult.resolveMessageCodes(MISSING_FIELD_ERROR_CODE, missingField); 061 Object[] arguments = getArgumentsForBindError(bindingResult.getObjectName(), fixedField); 062 FieldError error = new FieldError(bindingResult.getObjectName(), fixedField, "", true, 063 codes, arguments, "Field '" + fixedField + "' is required"); 064 bindingResult.addError(error); 065 } 066 067 @Override 068 public void processPropertyAccessException(PropertyAccessException ex, BindingResult bindingResult) { 069 // Create field error with the exceptions's code, e.g. "typeMismatch". 070 String field = ex.getPropertyName(); 071 Assert.state(field != null, "No field in exception"); 072 String[] codes = bindingResult.resolveMessageCodes(ex.getErrorCode(), field); 073 Object[] arguments = getArgumentsForBindError(bindingResult.getObjectName(), field); 074 Object rejectedValue = ex.getValue(); 075 if (ObjectUtils.isArray(rejectedValue)) { 076 rejectedValue = StringUtils.arrayToCommaDelimitedString(ObjectUtils.toObjectArray(rejectedValue)); 077 } 078 FieldError error = new FieldError(bindingResult.getObjectName(), field, rejectedValue, true, 079 codes, arguments, ex.getLocalizedMessage()); 080 error.wrap(ex); 081 bindingResult.addError(error); 082 } 083 084 /** 085 * Return FieldError arguments for a binding error on the given field. 086 * Invoked for each missing required field and each type mismatch. 087 * <p>The default implementation returns a single argument indicating the field name 088 * (of type DefaultMessageSourceResolvable, with "objectName.field" and "field" as codes). 089 * @param objectName the name of the target object 090 * @param field the field that caused the binding error 091 * @return the Object array that represents the FieldError arguments 092 * @see org.springframework.validation.FieldError#getArguments 093 * @see org.springframework.context.support.DefaultMessageSourceResolvable 094 */ 095 protected Object[] getArgumentsForBindError(String objectName, String field) { 096 String[] codes = new String[] {objectName + Errors.NESTED_PATH_SEPARATOR + field, field}; 097 return new Object[] {new DefaultMessageSourceResolvable(codes, field)}; 098 } 099 100}