1 /*
2  * Copyright 2002-2011 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package org.springframework.validation;
18 
19 import java.beans.PropertyEditor;
20 import java.util.HashMap;
21 import java.util.Map;
22 
23 import org.apache.commons.logging.Log;
24 import org.apache.commons.logging.LogFactory;
25 
26 import org.springframework.beans.ConfigurablePropertyAccessor;
27 import org.springframework.beans.MutablePropertyValues;
28 import org.springframework.beans.PropertyAccessException;
29 import org.springframework.beans.PropertyAccessorUtils;
30 import org.springframework.beans.PropertyBatchUpdateException;
31 import org.springframework.beans.PropertyEditorRegistry;
32 import org.springframework.beans.PropertyValue;
33 import org.springframework.beans.PropertyValues;
34 import org.springframework.beans.SimpleTypeConverter;
35 import org.springframework.beans.TypeConverter;
36 import org.springframework.beans.TypeMismatchException;
37 import org.springframework.core.MethodParameter;
38 import org.springframework.core.convert.ConversionService;
39 import org.springframework.util.Assert;
40 import org.springframework.util.ObjectUtils;
41 import org.springframework.util.PatternMatchUtils;
42 import org.springframework.util.StringUtils;
43 
44 /**
45  * Binder that allows for setting property values onto a target object,
46  * including support for validation and binding result analysis.
47  * The binding process can be customized through specifying allowed fields,
48  * required fields, custom editors, etc.
49  *
50  * <p>Note that there are potential security implications in failing to set an array
51  * of allowed fields. In the case of HTTP form POST data for example, malicious clients
52  * can attempt to subvert an application by supplying values for fields or properties
53  * that do not exist on the form. In some cases this could lead to illegal data being
54  * set on command objects <i>or their nested objects</i>. For this reason, it is
55  * <b>highly recommended to specify the {@link #setAllowedFields allowedFields} property</b>
56  * on the DataBinder.
57  *
58  * <p>The binding results can be examined via the {@link BindingResult} interface,
59  * extending the {@link Errors} interface: see the {@link #getBindingResult()} method.
60  * Missing fields and property access exceptions will be converted to {@link FieldError FieldErrors},
61  * collected in the Errors instance, using the following error codes:
62  *
63  * <ul>
64  * <li>Missing field error: "required"
65  * <li>Type mismatch error: "typeMismatch"
66  * <li>Method invocation error: "methodInvocation"
67  * </ul>
68  *
69  * <p>By default, binding errors get resolved through the {@link BindingErrorProcessor}
70  * strategy, processing for missing fields and property access exceptions: see the
71  * {@link #setBindingErrorProcessor} method. You can override the default strategy
72  * if needed, for example to generate different error codes.
73  *
74  * <p>Custom validation errors can be added afterwards. You will typically want to resolve
75  * such error codes into proper user-visible error messages; this can be achieved through
76  * resolving each error via a {@link org.springframework.context.MessageSource}, which is
77  * able to resolve an {@link ObjectError}/{@link FieldError} through its
78  * {@link org.springframework.context.MessageSource#getMessage(org.springframework.context.MessageSourceResolvable, java.util.Locale)}
79  * method. The list of message codes can be customized through the {@link MessageCodesResolver}
80  * strategy: see the {@link #setMessageCodesResolver} method. {@link DefaultMessageCodesResolver}'s
81  * javadoc states details on the default resolution rules.
82  *
83  * <p>This generic data binder can be used in any kind of environment.
84  * It is typically used by Spring web MVC controllers, via the web-specific
85  * subclasses {@link org.springframework.web.bind.ServletRequestDataBinder}
86  * and {@link org.springframework.web.portlet.bind.PortletRequestDataBinder}.
87  *
88  * @author Rod Johnson
89  * @author Juergen Hoeller
90  * @author Rob Harrop
91  * @see #setAllowedFields
92  * @see #setRequiredFields
93  * @see #registerCustomEditor
94  * @see #setMessageCodesResolver
95  * @see #setBindingErrorProcessor
96  * @see #bind
97  * @see #getBindingResult
98  * @see DefaultMessageCodesResolver
99  * @see DefaultBindingErrorProcessor
100  * @see org.springframework.context.MessageSource
101  * @see org.springframework.web.bind.ServletRequestDataBinder
102  */
103 public class DataBinder implements PropertyEditorRegistry, TypeConverter {
104 
105 	/** Default object name used for binding: "target" */
106 	public static final String DEFAULT_OBJECT_NAME = "target";
107 
108 	/** Default limit for array and collection growing: 256 */
109 	public static final int DEFAULT_AUTO_GROW_COLLECTION_LIMIT = 256;
110 
111 
112 	/**
113 	 * We'll create a lot of DataBinder instances: Let's use a static logger.
114 	 */
115 	protected static final Log logger = LogFactory.getLog(DataBinder.class);
116 
117 	private final Object target;
118 
119 	private final String objectName;
120 
121 	private AbstractPropertyBindingResult bindingResult;
122 
123 	private SimpleTypeConverter typeConverter;
124 
125 	private BindException bindException;
126 
127 	private boolean ignoreUnknownFields = true;
128 
129 	private boolean ignoreInvalidFields = false;
130 
131 	private boolean autoGrowNestedPaths = true;
132 
133 	private int autoGrowCollectionLimit = DEFAULT_AUTO_GROW_COLLECTION_LIMIT;
134 
135 	private String[] allowedFields;
136 
137 	private String[] disallowedFields;
138 
139 	private String[] requiredFields;
140 
141 	private BindingErrorProcessor bindingErrorProcessor = new DefaultBindingErrorProcessor();
142 
143 	private Validator validator;
144 
145 	private ConversionService conversionService;
146 
147 
148 	/**
149 	 * Create a new DataBinder instance, with default object name.
150 	 * @param target the target object to bind onto (or <code>null</code>
151 	 * if the binder is just used to convert a plain parameter value)
152 	 * @see #DEFAULT_OBJECT_NAME
153 	 */
DataBinder(Object target)154 	public DataBinder(Object target) {
155 		this(target, DEFAULT_OBJECT_NAME);
156 	}
157 
158 	/**
159 	 * Create a new DataBinder instance.
160 	 * @param target the target object to bind onto (or <code>null</code>
161 	 * if the binder is just used to convert a plain parameter value)
162 	 * @param objectName the name of the target object
163 	 */
DataBinder(Object target, String objectName)164 	public DataBinder(Object target, String objectName) {
165 		this.target = target;
166 		this.objectName = objectName;
167 	}
168 
169 
170 	/**
171 	 * Return the wrapped target object.
172 	 */
getTarget()173 	public Object getTarget() {
174 		return this.target;
175 	}
176 
177 	/**
178 	 * Return the name of the bound object.
179 	 */
getObjectName()180 	public String getObjectName() {
181 		return this.objectName;
182 	}
183 
184 	/**
185 	 * Set whether this binder should attempt to "auto-grow" a nested path that contains a null value.
186 	 * <p>If "true", a null path location will be populated with a default object value and traversed
187 	 * instead of resulting in an exception. This flag also enables auto-growth of collection elements
188 	 * when accessing an out-of-bounds index.
189 	 * <p>Default is "true" on a standard DataBinder. Note that this feature is only supported
190 	 * for bean property access (DataBinder's default mode), not for field access.
191 	 * @see #initBeanPropertyAccess()
192 	 * @see org.springframework.beans.BeanWrapper#setAutoGrowNestedPaths
193 	 */
setAutoGrowNestedPaths(boolean autoGrowNestedPaths)194 	public void setAutoGrowNestedPaths(boolean autoGrowNestedPaths) {
195 		Assert.state(this.bindingResult == null,
196 				"DataBinder is already initialized - call setAutoGrowNestedPaths before other configuration methods");
197 		this.autoGrowNestedPaths = autoGrowNestedPaths;
198 	}
199 
200 	/**
201 	 * Return whether "auto-growing" of nested paths has been activated.
202 	 */
isAutoGrowNestedPaths()203 	public boolean isAutoGrowNestedPaths() {
204 		return this.autoGrowNestedPaths;
205 	}
206 
207 	/**
208 	 * Specify the limit for array and collection auto-growing.
209 	 * <p>Default is 256, preventing OutOfMemoryErrors in case of large indexes.
210 	 * Raise this limit if your auto-growing needs are unusually high.
211 	 */
setAutoGrowCollectionLimit(int autoGrowCollectionLimit)212 	public void setAutoGrowCollectionLimit(int autoGrowCollectionLimit) {
213 		this.autoGrowCollectionLimit = autoGrowCollectionLimit;
214 	}
215 
216 	/**
217 	 * Return the current limit for array and collection auto-growing.
218 	 */
getAutoGrowCollectionLimit()219 	public int getAutoGrowCollectionLimit() {
220 		return this.autoGrowCollectionLimit;
221 	}
222 
223 	/**
224 	 * Initialize standard JavaBean property access for this DataBinder.
225 	 * <p>This is the default; an explicit call just leads to eager initialization.
226 	 * @see #initDirectFieldAccess()
227 	 */
initBeanPropertyAccess()228 	public void initBeanPropertyAccess() {
229 		Assert.state(this.bindingResult == null,
230 				"DataBinder is already initialized - call initBeanPropertyAccess before other configuration methods");
231 		this.bindingResult = new BeanPropertyBindingResult(
232 				getTarget(), getObjectName(), isAutoGrowNestedPaths(), getAutoGrowCollectionLimit());
233 		if (this.conversionService != null) {
234 			this.bindingResult.initConversion(this.conversionService);
235 		}
236 	}
237 
238 	/**
239 	 * Initialize direct field access for this DataBinder,
240 	 * as alternative to the default bean property access.
241 	 * @see #initBeanPropertyAccess()
242 	 */
initDirectFieldAccess()243 	public void initDirectFieldAccess() {
244 		Assert.state(this.bindingResult == null,
245 				"DataBinder is already initialized - call initDirectFieldAccess before other configuration methods");
246 		this.bindingResult = new DirectFieldBindingResult(getTarget(), getObjectName());
247 		if (this.conversionService != null) {
248 			this.bindingResult.initConversion(this.conversionService);
249 		}
250 	}
251 
252 	/**
253 	 * Return the internal BindingResult held by this DataBinder,
254 	 * as AbstractPropertyBindingResult.
255 	 */
getInternalBindingResult()256 	protected AbstractPropertyBindingResult getInternalBindingResult() {
257 		if (this.bindingResult == null) {
258 			initBeanPropertyAccess();
259 		}
260 		return this.bindingResult;
261 	}
262 
263 	/**
264 	 * Return the underlying PropertyAccessor of this binder's BindingResult.
265 	 */
getPropertyAccessor()266 	protected ConfigurablePropertyAccessor getPropertyAccessor() {
267 		return getInternalBindingResult().getPropertyAccessor();
268 	}
269 
270 	/**
271 	 * Return this binder's underlying SimpleTypeConverter.
272 	 */
getSimpleTypeConverter()273 	protected SimpleTypeConverter getSimpleTypeConverter() {
274 		if (this.typeConverter == null) {
275 			this.typeConverter = new SimpleTypeConverter();
276 			if (this.conversionService != null) {
277 				this.typeConverter.setConversionService(this.conversionService);
278 			}
279 		}
280 		return this.typeConverter;
281 	}
282 
283 	/**
284 	 * Return the underlying TypeConverter of this binder's BindingResult.
285 	 */
getPropertyEditorRegistry()286 	protected PropertyEditorRegistry getPropertyEditorRegistry() {
287 		if (getTarget() != null) {
288 			return getInternalBindingResult().getPropertyAccessor();
289 		}
290 		else {
291 			return getSimpleTypeConverter();
292 		}
293 	}
294 
295 	/**
296 	 * Return the underlying TypeConverter of this binder's BindingResult.
297 	 */
getTypeConverter()298 	protected TypeConverter getTypeConverter() {
299 		if (getTarget() != null) {
300 			return getInternalBindingResult().getPropertyAccessor();
301 		}
302 		else {
303 			return getSimpleTypeConverter();
304 		}
305 	}
306 
307 	/**
308 	 * Return the BindingResult instance created by this DataBinder.
309 	 * This allows for convenient access to the binding results after
310 	 * a bind operation.
311 	 * @return the BindingResult instance, to be treated as BindingResult
312 	 * or as Errors instance (Errors is a super-interface of BindingResult)
313 	 * @see Errors
314 	 * @see #bind
315 	 */
getBindingResult()316 	public BindingResult getBindingResult() {
317 		return getInternalBindingResult();
318 	}
319 
320 	/**
321 	 * Return the Errors instance for this data binder.
322 	 * @return the Errors instance, to be treated as Errors or as BindException
323 	 * @deprecated in favor of {@link #getBindingResult()}.
324 	 * Use the {@link BindException#BindException(BindingResult)} constructor
325 	 * to create a BindException instance if still needed.
326 	 * @see #getBindingResult()
327 	 */
328 	@Deprecated
getErrors()329 	public BindException getErrors() {
330 		if (this.bindException == null) {
331 			this.bindException = new BindException(getBindingResult());
332 		}
333 		return this.bindException;
334 	}
335 
336 
337 	/**
338 	 * Set whether to ignore unknown fields, that is, whether to ignore bind
339 	 * parameters that do not have corresponding fields in the target object.
340 	 * <p>Default is "true". Turn this off to enforce that all bind parameters
341 	 * must have a matching field in the target object.
342 	 * <p>Note that this setting only applies to <i>binding</i> operations
343 	 * on this DataBinder, not to <i>retrieving</i> values via its
344 	 * {@link #getBindingResult() BindingResult}.
345 	 * @see #bind
346 	 */
setIgnoreUnknownFields(boolean ignoreUnknownFields)347 	public void setIgnoreUnknownFields(boolean ignoreUnknownFields) {
348 		this.ignoreUnknownFields = ignoreUnknownFields;
349 	}
350 
351 	/**
352 	 * Return whether to ignore unknown fields when binding.
353 	 */
isIgnoreUnknownFields()354 	public boolean isIgnoreUnknownFields() {
355 		return this.ignoreUnknownFields;
356 	}
357 
358 	/**
359 	 * Set whether to ignore invalid fields, that is, whether to ignore bind
360 	 * parameters that have corresponding fields in the target object which are
361 	 * not accessible (for example because of null values in the nested path).
362 	 * <p>Default is "false". Turn this on to ignore bind parameters for
363 	 * nested objects in non-existing parts of the target object graph.
364 	 * <p>Note that this setting only applies to <i>binding</i> operations
365 	 * on this DataBinder, not to <i>retrieving</i> values via its
366 	 * {@link #getBindingResult() BindingResult}.
367 	 * @see #bind
368 	 */
setIgnoreInvalidFields(boolean ignoreInvalidFields)369 	public void setIgnoreInvalidFields(boolean ignoreInvalidFields) {
370 		this.ignoreInvalidFields = ignoreInvalidFields;
371 	}
372 
373 	/**
374 	 * Return whether to ignore invalid fields when binding.
375 	 */
isIgnoreInvalidFields()376 	public boolean isIgnoreInvalidFields() {
377 		return this.ignoreInvalidFields;
378 	}
379 
380 	/**
381 	 * Register fields that should be allowed for binding. Default is all
382 	 * fields. Restrict this for example to avoid unwanted modifications
383 	 * by malicious users when binding HTTP request parameters.
384 	 * <p>Supports "xxx*", "*xxx" and "*xxx*" patterns. More sophisticated matching
385 	 * can be implemented by overriding the <code>isAllowed</code> method.
386 	 * <p>Alternatively, specify a list of <i>disallowed</i> fields.
387 	 * @param allowedFields array of field names
388 	 * @see #setDisallowedFields
389 	 * @see #isAllowed(String)
390 	 * @see org.springframework.web.bind.ServletRequestDataBinder
391 	 */
setAllowedFields(String... allowedFields)392 	public void setAllowedFields(String... allowedFields) {
393 		this.allowedFields = PropertyAccessorUtils.canonicalPropertyNames(allowedFields);
394 	}
395 
396 	/**
397 	 * Return the fields that should be allowed for binding.
398 	 * @return array of field names
399 	 */
getAllowedFields()400 	public String[] getAllowedFields() {
401 		return this.allowedFields;
402 	}
403 
404 	/**
405 	 * Register fields that should <i>not</i> be allowed for binding. Default is none.
406 	 * Mark fields as disallowed for example to avoid unwanted modifications
407 	 * by malicious users when binding HTTP request parameters.
408 	 * <p>Supports "xxx*", "*xxx" and "*xxx*" patterns. More sophisticated matching
409 	 * can be implemented by overriding the <code>isAllowed</code> method.
410 	 * <p>Alternatively, specify a list of <i>allowed</i> fields.
411 	 * @param disallowedFields array of field names
412 	 * @see #setAllowedFields
413 	 * @see #isAllowed(String)
414 	 * @see org.springframework.web.bind.ServletRequestDataBinder
415 	 */
setDisallowedFields(String... disallowedFields)416 	public void setDisallowedFields(String... disallowedFields) {
417 		this.disallowedFields = PropertyAccessorUtils.canonicalPropertyNames(disallowedFields);
418 	}
419 
420 	/**
421 	 * Return the fields that should <i>not</i> be allowed for binding.
422 	 * @return array of field names
423 	 */
getDisallowedFields()424 	public String[] getDisallowedFields() {
425 		return this.disallowedFields;
426 	}
427 
428 	/**
429 	 * Register fields that are required for each binding process.
430 	 * <p>If one of the specified fields is not contained in the list of
431 	 * incoming property values, a corresponding "missing field" error
432 	 * will be created, with error code "required" (by the default
433 	 * binding error processor).
434 	 * @param requiredFields array of field names
435 	 * @see #setBindingErrorProcessor
436 	 * @see DefaultBindingErrorProcessor#MISSING_FIELD_ERROR_CODE
437 	 */
setRequiredFields(String... requiredFields)438 	public void setRequiredFields(String... requiredFields) {
439 		this.requiredFields = PropertyAccessorUtils.canonicalPropertyNames(requiredFields);
440 		if (logger.isDebugEnabled()) {
441 			logger.debug("DataBinder requires binding of required fields [" +
442 					StringUtils.arrayToCommaDelimitedString(requiredFields) + "]");
443 		}
444 	}
445 
446 	/**
447 	 * Return the fields that are required for each binding process.
448 	 * @return array of field names
449 	 */
getRequiredFields()450 	public String[] getRequiredFields() {
451 		return this.requiredFields;
452 	}
453 
454 	/**
455 	 * Set whether to extract the old field value when applying a
456 	 * property editor to a new value for a field.
457 	 * <p>Default is "true", exposing previous field values to custom editors.
458 	 * Turn this to "false" to avoid side effects caused by getters.
459 	 */
setExtractOldValueForEditor(boolean extractOldValueForEditor)460 	public void setExtractOldValueForEditor(boolean extractOldValueForEditor) {
461 		getPropertyAccessor().setExtractOldValueForEditor(extractOldValueForEditor);
462 	}
463 
464 	/**
465 	 * Set the strategy to use for resolving errors into message codes.
466 	 * Applies the given strategy to the underlying errors holder.
467 	 * <p>Default is a DefaultMessageCodesResolver.
468 	 * @see BeanPropertyBindingResult#setMessageCodesResolver
469 	 * @see DefaultMessageCodesResolver
470 	 */
setMessageCodesResolver(MessageCodesResolver messageCodesResolver)471 	public void setMessageCodesResolver(MessageCodesResolver messageCodesResolver) {
472 		getInternalBindingResult().setMessageCodesResolver(messageCodesResolver);
473 	}
474 
475 	/**
476 	 * Set the strategy to use for processing binding errors, that is,
477 	 * required field errors and <code>PropertyAccessException</code>s.
478 	 * <p>Default is a DefaultBindingErrorProcessor.
479 	 * @see DefaultBindingErrorProcessor
480 	 */
setBindingErrorProcessor(BindingErrorProcessor bindingErrorProcessor)481 	public void setBindingErrorProcessor(BindingErrorProcessor bindingErrorProcessor) {
482 		Assert.notNull(bindingErrorProcessor, "BindingErrorProcessor must not be null");
483 		this.bindingErrorProcessor = bindingErrorProcessor;
484 	}
485 
486 	/**
487 	 * Return the strategy for processing binding errors.
488 	 */
getBindingErrorProcessor()489 	public BindingErrorProcessor getBindingErrorProcessor() {
490 		return this.bindingErrorProcessor;
491 	}
492 
493 	/**
494 	 * Set the Validator to apply after each binding step.
495 	 */
setValidator(Validator validator)496 	public void setValidator(Validator validator) {
497 		if (validator != null && (getTarget() != null && !validator.supports(getTarget().getClass()))) {
498 			throw new IllegalStateException("Invalid target for Validator [" + validator + "]: " + getTarget());
499 		}
500 		this.validator = validator;
501 	}
502 
503 	/**
504 	 * Return the Validator to apply after each binding step, if any.
505 	 */
getValidator()506 	public Validator getValidator() {
507 		return this.validator;
508 	}
509 
510 
511 	//---------------------------------------------------------------------
512 	// Implementation of PropertyEditorRegistry/TypeConverter interface
513 	//---------------------------------------------------------------------
514 
515 	/**
516 	 * Specify a Spring 3.0 ConversionService to use for converting
517 	 * property values, as an alternative to JavaBeans PropertyEditors.
518 	 */
setConversionService(ConversionService conversionService)519 	public void setConversionService(ConversionService conversionService) {
520 		Assert.state(this.conversionService == null, "DataBinder is already initialized with ConversionService");
521 		this.conversionService = conversionService;
522 		if (this.bindingResult != null && conversionService != null) {
523 			this.bindingResult.initConversion(conversionService);
524 		}
525 	}
526 
527 	/**
528 	 * Return the associated ConversionService, if any.
529 	 */
getConversionService()530 	public ConversionService getConversionService() {
531 		return this.conversionService;
532 	}
533 
registerCustomEditor(Class<?> requiredType, PropertyEditor propertyEditor)534 	public void registerCustomEditor(Class<?> requiredType, PropertyEditor propertyEditor) {
535 		getPropertyEditorRegistry().registerCustomEditor(requiredType, propertyEditor);
536 	}
537 
registerCustomEditor(Class<?> requiredType, String field, PropertyEditor propertyEditor)538 	public void registerCustomEditor(Class<?> requiredType, String field, PropertyEditor propertyEditor) {
539 		getPropertyEditorRegistry().registerCustomEditor(requiredType, field, propertyEditor);
540 	}
541 
findCustomEditor(Class<?> requiredType, String propertyPath)542 	public PropertyEditor findCustomEditor(Class<?> requiredType, String propertyPath) {
543 		return getPropertyEditorRegistry().findCustomEditor(requiredType, propertyPath);
544 	}
545 
convertIfNecessary(Object value, Class<T> requiredType)546 	public <T> T convertIfNecessary(Object value, Class<T> requiredType) throws TypeMismatchException {
547 		return getTypeConverter().convertIfNecessary(value, requiredType);
548 	}
549 
convertIfNecessary( Object value, Class<T> requiredType, MethodParameter methodParam)550 	public <T> T convertIfNecessary(
551 			Object value, Class<T> requiredType, MethodParameter methodParam) throws TypeMismatchException {
552 
553 		return getTypeConverter().convertIfNecessary(value, requiredType, methodParam);
554 	}
555 
556 
557 	/**
558 	 * Bind the given property values to this binder's target.
559 	 * <p>This call can create field errors, representing basic binding
560 	 * errors like a required field (code "required"), or type mismatch
561 	 * between value and bean property (code "typeMismatch").
562 	 * <p>Note that the given PropertyValues should be a throwaway instance:
563 	 * For efficiency, it will be modified to just contain allowed fields if it
564 	 * implements the MutablePropertyValues interface; else, an internal mutable
565 	 * copy will be created for this purpose. Pass in a copy of the PropertyValues
566 	 * if you want your original instance to stay unmodified in any case.
567 	 * @param pvs property values to bind
568 	 * @see #doBind(org.springframework.beans.MutablePropertyValues)
569 	 */
bind(PropertyValues pvs)570 	public void bind(PropertyValues pvs) {
571 		MutablePropertyValues mpvs = (pvs instanceof MutablePropertyValues) ?
572 				(MutablePropertyValues) pvs : new MutablePropertyValues(pvs);
573 		doBind(mpvs);
574 	}
575 
576 	/**
577 	 * Actual implementation of the binding process, working with the
578 	 * passed-in MutablePropertyValues instance.
579 	 * @param mpvs the property values to bind,
580 	 * as MutablePropertyValues instance
581 	 * @see #checkAllowedFields
582 	 * @see #checkRequiredFields
583 	 * @see #applyPropertyValues
584 	 */
doBind(MutablePropertyValues mpvs)585 	protected void doBind(MutablePropertyValues mpvs) {
586 		checkAllowedFields(mpvs);
587 		checkRequiredFields(mpvs);
588 		applyPropertyValues(mpvs);
589 	}
590 
591 	/**
592 	 * Check the given property values against the allowed fields,
593 	 * removing values for fields that are not allowed.
594 	 * @param mpvs the property values to be bound (can be modified)
595 	 * @see #getAllowedFields
596 	 * @see #isAllowed(String)
597 	 */
checkAllowedFields(MutablePropertyValues mpvs)598 	protected void checkAllowedFields(MutablePropertyValues mpvs) {
599 		PropertyValue[] pvs = mpvs.getPropertyValues();
600 		for (PropertyValue pv : pvs) {
601 			String field = PropertyAccessorUtils.canonicalPropertyName(pv.getName());
602 			if (!isAllowed(field)) {
603 				mpvs.removePropertyValue(pv);
604 				getBindingResult().recordSuppressedField(field);
605 				if (logger.isDebugEnabled()) {
606 					logger.debug("Field [" + field + "] has been removed from PropertyValues " +
607 							"and will not be bound, because it has not been found in the list of allowed fields");
608 				}
609 			}
610 		}
611 	}
612 
613 	/**
614 	 * Return if the given field is allowed for binding.
615 	 * Invoked for each passed-in property value.
616 	 * <p>The default implementation checks for "xxx*", "*xxx" and "*xxx*" matches,
617 	 * as well as direct equality, in the specified lists of allowed fields and
618 	 * disallowed fields. A field matching a disallowed pattern will not be accepted
619 	 * even if it also happens to match a pattern in the allowed list.
620 	 * <p>Can be overridden in subclasses.
621 	 * @param field the field to check
622 	 * @return if the field is allowed
623 	 * @see #setAllowedFields
624 	 * @see #setDisallowedFields
625 	 * @see org.springframework.util.PatternMatchUtils#simpleMatch(String, String)
626 	 */
isAllowed(String field)627 	protected boolean isAllowed(String field) {
628 		String[] allowed = getAllowedFields();
629 		String[] disallowed = getDisallowedFields();
630 		return ((ObjectUtils.isEmpty(allowed) || PatternMatchUtils.simpleMatch(allowed, field)) &&
631 				(ObjectUtils.isEmpty(disallowed) || !PatternMatchUtils.simpleMatch(disallowed, field)));
632 	}
633 
634 	/**
635 	 * Check the given property values against the required fields,
636 	 * generating missing field errors where appropriate.
637 	 * @param mpvs the property values to be bound (can be modified)
638 	 * @see #getRequiredFields
639 	 * @see #getBindingErrorProcessor
640 	 * @see BindingErrorProcessor#processMissingFieldError
641 	 */
checkRequiredFields(MutablePropertyValues mpvs)642 	protected void checkRequiredFields(MutablePropertyValues mpvs) {
643 		String[] requiredFields = getRequiredFields();
644 		if (!ObjectUtils.isEmpty(requiredFields)) {
645 			Map<String, PropertyValue> propertyValues = new HashMap<String, PropertyValue>();
646 			PropertyValue[] pvs = mpvs.getPropertyValues();
647 			for (PropertyValue pv : pvs) {
648 				String canonicalName = PropertyAccessorUtils.canonicalPropertyName(pv.getName());
649 				propertyValues.put(canonicalName, pv);
650 			}
651 			for (String field : requiredFields) {
652 				PropertyValue pv = propertyValues.get(field);
653 				boolean empty = (pv == null || pv.getValue() == null);
654 				if (!empty) {
655 					if (pv.getValue() instanceof String) {
656 						empty = !StringUtils.hasText((String) pv.getValue());
657 					}
658 					else if (pv.getValue() instanceof String[]) {
659 						String[] values = (String[]) pv.getValue();
660 						empty = (values.length == 0 || !StringUtils.hasText(values[0]));
661 					}
662 				}
663 				if (empty) {
664 					// Use bind error processor to create FieldError.
665 					getBindingErrorProcessor().processMissingFieldError(field, getInternalBindingResult());
666 					// Remove property from property values to bind:
667 					// It has already caused a field error with a rejected value.
668 					if (pv != null) {
669 						mpvs.removePropertyValue(pv);
670 						propertyValues.remove(field);
671 					}
672 				}
673 			}
674 		}
675 	}
676 
677 	/**
678 	 * Apply given property values to the target object.
679 	 * <p>Default implementation applies all of the supplied property
680 	 * values as bean property values. By default, unknown fields will
681 	 * be ignored.
682 	 * @param mpvs the property values to be bound (can be modified)
683 	 * @see #getTarget
684 	 * @see #getPropertyAccessor
685 	 * @see #isIgnoreUnknownFields
686 	 * @see #getBindingErrorProcessor
687 	 * @see BindingErrorProcessor#processPropertyAccessException
688 	 */
applyPropertyValues(MutablePropertyValues mpvs)689 	protected void applyPropertyValues(MutablePropertyValues mpvs) {
690 		try {
691 			// Bind request parameters onto target object.
692 			getPropertyAccessor().setPropertyValues(mpvs, isIgnoreUnknownFields(), isIgnoreInvalidFields());
693 		}
694 		catch (PropertyBatchUpdateException ex) {
695 			// Use bind error processor to create FieldErrors.
696 			for (PropertyAccessException pae : ex.getPropertyAccessExceptions()) {
697 				getBindingErrorProcessor().processPropertyAccessException(pae, getInternalBindingResult());
698 			}
699 		}
700 	}
701 
702 
703 	/**
704 	 * Invoke the specified Validator, if any.
705 	 * @see #setValidator(Validator)
706 	 * @see #getBindingResult()
707 	 */
validate()708 	public void validate() {
709 		this.validator.validate(getTarget(), getBindingResult());
710 	}
711 
712 	/**
713 	 * Invoke the specified Validator, if any, with the given validation hints.
714 	 * <p>Note: Validation hints may get ignored by the actual target Validator.
715 	 * @param validationHints one or more hint objects to be passed to a {@link SmartValidator}
716 	 * @see #setValidator(Validator)
717 	 * @see SmartValidator#validate(Object, Errors, Object...)
718 	 */
validate(Object... validationHints)719 	public void validate(Object... validationHints) {
720 		Validator validator = getValidator();
721 		if (!ObjectUtils.isEmpty(validationHints) && validator instanceof SmartValidator) {
722 			((SmartValidator) validator).validate(getTarget(), getBindingResult(), validationHints);
723 		}
724 		else if (validator != null) {
725 			validator.validate(getTarget(), getBindingResult());
726 		}
727 	}
728 
729 	/**
730 	 * Close this DataBinder, which may result in throwing
731 	 * a BindException if it encountered any errors.
732 	 * @return the model Map, containing target object and Errors instance
733 	 * @throws BindException if there were any errors in the bind operation
734 	 * @see BindingResult#getModel()
735 	 */
close()736 	public Map<?, ?> close() throws BindException {
737 		if (getBindingResult().hasErrors()) {
738 			throw new BindException(getBindingResult());
739 		}
740 		return getBindingResult().getModel();
741 	}
742 
743 }
744