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 java.beans.PropertyEditor;
020import java.lang.reflect.Field;
021import java.util.ArrayList;
022import java.util.Arrays;
023import java.util.Collections;
024import java.util.HashMap;
025import java.util.List;
026import java.util.Map;
027import java.util.Optional;
028
029import org.apache.commons.logging.Log;
030import org.apache.commons.logging.LogFactory;
031
032import org.springframework.beans.ConfigurablePropertyAccessor;
033import org.springframework.beans.MutablePropertyValues;
034import org.springframework.beans.PropertyAccessException;
035import org.springframework.beans.PropertyAccessorUtils;
036import org.springframework.beans.PropertyBatchUpdateException;
037import org.springframework.beans.PropertyEditorRegistry;
038import org.springframework.beans.PropertyValue;
039import org.springframework.beans.PropertyValues;
040import org.springframework.beans.SimpleTypeConverter;
041import org.springframework.beans.TypeConverter;
042import org.springframework.beans.TypeMismatchException;
043import org.springframework.core.MethodParameter;
044import org.springframework.core.convert.ConversionService;
045import org.springframework.format.Formatter;
046import org.springframework.format.support.FormatterPropertyEditorAdapter;
047import org.springframework.lang.UsesJava8;
048import org.springframework.util.Assert;
049import org.springframework.util.ClassUtils;
050import org.springframework.util.ObjectUtils;
051import org.springframework.util.PatternMatchUtils;
052import org.springframework.util.StringUtils;
053
054/**
055 * Binder that allows for setting property values onto a target object,
056 * including support for validation and binding result analysis.
057 * The binding process can be customized through specifying allowed fields,
058 * required fields, custom editors, etc.
059 *
060 * <p>Note that there are potential security implications in failing to set an array
061 * of allowed fields. In the case of HTTP form POST data for example, malicious clients
062 * can attempt to subvert an application by supplying values for fields or properties
063 * that do not exist on the form. In some cases this could lead to illegal data being
064 * set on command objects <i>or their nested objects</i>. For this reason, it is
065 * <b>highly recommended to specify the {@link #setAllowedFields allowedFields} property</b>
066 * on the DataBinder.
067 *
068 * <p>The binding results can be examined via the {@link BindingResult} interface,
069 * extending the {@link Errors} interface: see the {@link #getBindingResult()} method.
070 * Missing fields and property access exceptions will be converted to {@link FieldError FieldErrors},
071 * collected in the Errors instance, using the following error codes:
072 *
073 * <ul>
074 * <li>Missing field error: "required"
075 * <li>Type mismatch error: "typeMismatch"
076 * <li>Method invocation error: "methodInvocation"
077 * </ul>
078 *
079 * <p>By default, binding errors get resolved through the {@link BindingErrorProcessor}
080 * strategy, processing for missing fields and property access exceptions: see the
081 * {@link #setBindingErrorProcessor} method. You can override the default strategy
082 * if needed, for example to generate different error codes.
083 *
084 * <p>Custom validation errors can be added afterwards. You will typically want to resolve
085 * such error codes into proper user-visible error messages; this can be achieved through
086 * resolving each error via a {@link org.springframework.context.MessageSource}, which is
087 * able to resolve an {@link ObjectError}/{@link FieldError} through its
088 * {@link org.springframework.context.MessageSource#getMessage(org.springframework.context.MessageSourceResolvable, java.util.Locale)}
089 * method. The list of message codes can be customized through the {@link MessageCodesResolver}
090 * strategy: see the {@link #setMessageCodesResolver} method. {@link DefaultMessageCodesResolver}'s
091 * javadoc states details on the default resolution rules.
092 *
093 * <p>This generic data binder can be used in any kind of environment.
094 * It is typically used by Spring web MVC controllers, via the web-specific
095 * subclasses {@link org.springframework.web.bind.ServletRequestDataBinder}
096 * and {@link org.springframework.web.portlet.bind.PortletRequestDataBinder}.
097 *
098 * @author Rod Johnson
099 * @author Juergen Hoeller
100 * @author Rob Harrop
101 * @author Stephane Nicoll
102 * @author Kazuki Shimizu
103 * @see #setAllowedFields
104 * @see #setRequiredFields
105 * @see #registerCustomEditor
106 * @see #setMessageCodesResolver
107 * @see #setBindingErrorProcessor
108 * @see #bind
109 * @see #getBindingResult
110 * @see DefaultMessageCodesResolver
111 * @see DefaultBindingErrorProcessor
112 * @see org.springframework.context.MessageSource
113 * @see org.springframework.web.bind.ServletRequestDataBinder
114 */
115public class DataBinder implements PropertyEditorRegistry, TypeConverter {
116
117        /** Default object name used for binding: "target" */
118        public static final String DEFAULT_OBJECT_NAME = "target";
119
120        /** Default limit for array and collection growing: 256 */
121        public static final int DEFAULT_AUTO_GROW_COLLECTION_LIMIT = 256;
122
123
124        /**
125         * We'll create a lot of DataBinder instances: Let's use a static logger.
126         */
127        protected static final Log logger = LogFactory.getLog(DataBinder.class);
128
129        private static Class<?> javaUtilOptionalClass = null;
130
131        static {
132                try {
133                        javaUtilOptionalClass =
134                                        ClassUtils.forName("java.util.Optional", DataBinder.class.getClassLoader());
135                }
136                catch (ClassNotFoundException ex) {
137                        // Java 8 not available - Optional references simply not supported then.
138                }
139        }
140
141
142        private final Object target;
143
144        private final String objectName;
145
146        private AbstractPropertyBindingResult bindingResult;
147
148        private SimpleTypeConverter typeConverter;
149
150        private boolean ignoreUnknownFields = true;
151
152        private boolean ignoreInvalidFields = false;
153
154        private boolean autoGrowNestedPaths = true;
155
156        private int autoGrowCollectionLimit = DEFAULT_AUTO_GROW_COLLECTION_LIMIT;
157
158        private String[] allowedFields;
159
160        private String[] disallowedFields;
161
162        private String[] requiredFields;
163
164        private ConversionService conversionService;
165
166        private MessageCodesResolver messageCodesResolver;
167
168        private BindingErrorProcessor bindingErrorProcessor = new DefaultBindingErrorProcessor();
169
170        private final List<Validator> validators = new ArrayList<Validator>();
171
172
173        /**
174         * Create a new DataBinder instance, with default object name.
175         * @param target the target object to bind onto (or {@code null}
176         * if the binder is just used to convert a plain parameter value)
177         * @see #DEFAULT_OBJECT_NAME
178         */
179        public DataBinder(Object target) {
180                this(target, DEFAULT_OBJECT_NAME);
181        }
182
183        /**
184         * Create a new DataBinder instance.
185         * @param target the target object to bind onto (or {@code null}
186         * if the binder is just used to convert a plain parameter value)
187         * @param objectName the name of the target object
188         */
189        public DataBinder(Object target, String objectName) {
190                if (target != null && target.getClass() == javaUtilOptionalClass) {
191                        this.target = OptionalUnwrapper.unwrap(target);
192                }
193                else {
194                        this.target = target;
195                }
196                this.objectName = objectName;
197        }
198
199
200        /**
201         * Return the wrapped target object.
202         */
203        public Object getTarget() {
204                return this.target;
205        }
206
207        /**
208         * Return the name of the bound object.
209         */
210        public String getObjectName() {
211                return this.objectName;
212        }
213
214        /**
215         * Set whether this binder should attempt to "auto-grow" a nested path that contains a null value.
216         * <p>If "true", a null path location will be populated with a default object value and traversed
217         * instead of resulting in an exception. This flag also enables auto-growth of collection elements
218         * when accessing an out-of-bounds index.
219         * <p>Default is "true" on a standard DataBinder. Note that since Spring 4.1 this feature is supported
220         * for bean property access (DataBinder's default mode) and field access.
221         * @see #initBeanPropertyAccess()
222         * @see org.springframework.beans.BeanWrapper#setAutoGrowNestedPaths
223         */
224        public void setAutoGrowNestedPaths(boolean autoGrowNestedPaths) {
225                Assert.state(this.bindingResult == null,
226                                "DataBinder is already initialized - call setAutoGrowNestedPaths before other configuration methods");
227                this.autoGrowNestedPaths = autoGrowNestedPaths;
228        }
229
230        /**
231         * Return whether "auto-growing" of nested paths has been activated.
232         */
233        public boolean isAutoGrowNestedPaths() {
234                return this.autoGrowNestedPaths;
235        }
236
237        /**
238         * Specify the limit for array and collection auto-growing.
239         * <p>Default is 256, preventing OutOfMemoryErrors in case of large indexes.
240         * Raise this limit if your auto-growing needs are unusually high.
241         * @see #initBeanPropertyAccess()
242         * @see org.springframework.beans.BeanWrapper#setAutoGrowCollectionLimit
243         */
244        public void setAutoGrowCollectionLimit(int autoGrowCollectionLimit) {
245                Assert.state(this.bindingResult == null,
246                                "DataBinder is already initialized - call setAutoGrowCollectionLimit before other configuration methods");
247                this.autoGrowCollectionLimit = autoGrowCollectionLimit;
248        }
249
250        /**
251         * Return the current limit for array and collection auto-growing.
252         */
253        public int getAutoGrowCollectionLimit() {
254                return this.autoGrowCollectionLimit;
255        }
256
257        /**
258         * Initialize standard JavaBean property access for this DataBinder.
259         * <p>This is the default; an explicit call just leads to eager initialization.
260         * @see #initDirectFieldAccess()
261         * @see #createBeanPropertyBindingResult()
262         */
263        public void initBeanPropertyAccess() {
264                Assert.state(this.bindingResult == null,
265                                "DataBinder is already initialized - call initBeanPropertyAccess before other configuration methods");
266                this.bindingResult = createBeanPropertyBindingResult();
267        }
268
269        /**
270         * Create the {@link AbstractPropertyBindingResult} instance using standard
271         * JavaBean property access.
272         * @since 4.2.1
273         */
274        protected AbstractPropertyBindingResult createBeanPropertyBindingResult() {
275                BeanPropertyBindingResult result = new BeanPropertyBindingResult(getTarget(),
276                                getObjectName(), isAutoGrowNestedPaths(), getAutoGrowCollectionLimit());
277
278                if (this.conversionService != null) {
279                        result.initConversion(this.conversionService);
280                }
281                if (this.messageCodesResolver != null) {
282                        result.setMessageCodesResolver(this.messageCodesResolver);
283                }
284
285                return result;
286        }
287
288        /**
289         * Initialize direct field access for this DataBinder,
290         * as alternative to the default bean property access.
291         * @see #initBeanPropertyAccess()
292         * @see #createDirectFieldBindingResult()
293         */
294        public void initDirectFieldAccess() {
295                Assert.state(this.bindingResult == null,
296                                "DataBinder is already initialized - call initDirectFieldAccess before other configuration methods");
297                this.bindingResult = createDirectFieldBindingResult();
298        }
299
300        /**
301         * Create the {@link AbstractPropertyBindingResult} instance using direct
302         * field access.
303         * @since 4.2.1
304         */
305        protected AbstractPropertyBindingResult createDirectFieldBindingResult() {
306                DirectFieldBindingResult result = new DirectFieldBindingResult(getTarget(),
307                                getObjectName(), isAutoGrowNestedPaths());
308
309                if (this.conversionService != null) {
310                        result.initConversion(this.conversionService);
311                }
312                if (this.messageCodesResolver != null) {
313                        result.setMessageCodesResolver(this.messageCodesResolver);
314                }
315
316                return result;
317        }
318
319        /**
320         * Return the internal BindingResult held by this DataBinder,
321         * as an AbstractPropertyBindingResult.
322         */
323        protected AbstractPropertyBindingResult getInternalBindingResult() {
324                if (this.bindingResult == null) {
325                        initBeanPropertyAccess();
326                }
327                return this.bindingResult;
328        }
329
330        /**
331         * Return the underlying PropertyAccessor of this binder's BindingResult.
332         */
333        protected ConfigurablePropertyAccessor getPropertyAccessor() {
334                return getInternalBindingResult().getPropertyAccessor();
335        }
336
337        /**
338         * Return this binder's underlying SimpleTypeConverter.
339         */
340        protected SimpleTypeConverter getSimpleTypeConverter() {
341                if (this.typeConverter == null) {
342                        this.typeConverter = new SimpleTypeConverter();
343                        if (this.conversionService != null) {
344                                this.typeConverter.setConversionService(this.conversionService);
345                        }
346                }
347                return this.typeConverter;
348        }
349
350        /**
351         * Return the underlying TypeConverter of this binder's BindingResult.
352         */
353        protected PropertyEditorRegistry getPropertyEditorRegistry() {
354                if (getTarget() != null) {
355                        return getInternalBindingResult().getPropertyAccessor();
356                }
357                else {
358                        return getSimpleTypeConverter();
359                }
360        }
361
362        /**
363         * Return the underlying TypeConverter of this binder's BindingResult.
364         */
365        protected TypeConverter getTypeConverter() {
366                if (getTarget() != null) {
367                        return getInternalBindingResult().getPropertyAccessor();
368                }
369                else {
370                        return getSimpleTypeConverter();
371                }
372        }
373
374        /**
375         * Return the BindingResult instance created by this DataBinder.
376         * This allows for convenient access to the binding results after
377         * a bind operation.
378         * @return the BindingResult instance, to be treated as BindingResult
379         * or as Errors instance (Errors is a super-interface of BindingResult)
380         * @see Errors
381         * @see #bind
382         */
383        public BindingResult getBindingResult() {
384                return getInternalBindingResult();
385        }
386
387
388        /**
389         * Set whether to ignore unknown fields, that is, whether to ignore bind
390         * parameters that do not have corresponding fields in the target object.
391         * <p>Default is "true". Turn this off to enforce that all bind parameters
392         * must have a matching field in the target object.
393         * <p>Note that this setting only applies to <i>binding</i> operations
394         * on this DataBinder, not to <i>retrieving</i> values via its
395         * {@link #getBindingResult() BindingResult}.
396         * @see #bind
397         */
398        public void setIgnoreUnknownFields(boolean ignoreUnknownFields) {
399                this.ignoreUnknownFields = ignoreUnknownFields;
400        }
401
402        /**
403         * Return whether to ignore unknown fields when binding.
404         */
405        public boolean isIgnoreUnknownFields() {
406                return this.ignoreUnknownFields;
407        }
408
409        /**
410         * Set whether to ignore invalid fields, that is, whether to ignore bind
411         * parameters that have corresponding fields in the target object which are
412         * not accessible (for example because of null values in the nested path).
413         * <p>Default is "false". Turn this on to ignore bind parameters for
414         * nested objects in non-existing parts of the target object graph.
415         * <p>Note that this setting only applies to <i>binding</i> operations
416         * on this DataBinder, not to <i>retrieving</i> values via its
417         * {@link #getBindingResult() BindingResult}.
418         * @see #bind
419         */
420        public void setIgnoreInvalidFields(boolean ignoreInvalidFields) {
421                this.ignoreInvalidFields = ignoreInvalidFields;
422        }
423
424        /**
425         * Return whether to ignore invalid fields when binding.
426         */
427        public boolean isIgnoreInvalidFields() {
428                return this.ignoreInvalidFields;
429        }
430
431        /**
432         * Register fields that should be allowed for binding. Default is all
433         * fields. Restrict this for example to avoid unwanted modifications
434         * by malicious users when binding HTTP request parameters.
435         * <p>Supports "xxx*", "*xxx" and "*xxx*" patterns. More sophisticated matching
436         * can be implemented by overriding the {@code isAllowed} method.
437         * <p>Alternatively, specify a list of <i>disallowed</i> fields.
438         * @param allowedFields array of field names
439         * @see #setDisallowedFields
440         * @see #isAllowed(String)
441         * @see org.springframework.web.bind.ServletRequestDataBinder
442         */
443        public void setAllowedFields(String... allowedFields) {
444                this.allowedFields = PropertyAccessorUtils.canonicalPropertyNames(allowedFields);
445        }
446
447        /**
448         * Return the fields that should be allowed for binding.
449         * @return array of field names
450         */
451        public String[] getAllowedFields() {
452                return this.allowedFields;
453        }
454
455        /**
456         * Register fields that should <i>not</i> be allowed for binding. Default is none.
457         * Mark fields as disallowed for example to avoid unwanted modifications
458         * by malicious users when binding HTTP request parameters.
459         * <p>Supports "xxx*", "*xxx" and "*xxx*" patterns. More sophisticated matching
460         * can be implemented by overriding the {@code isAllowed} method.
461         * <p>Alternatively, specify a list of <i>allowed</i> fields.
462         * @param disallowedFields array of field names
463         * @see #setAllowedFields
464         * @see #isAllowed(String)
465         * @see org.springframework.web.bind.ServletRequestDataBinder
466         */
467        public void setDisallowedFields(String... disallowedFields) {
468                this.disallowedFields = PropertyAccessorUtils.canonicalPropertyNames(disallowedFields);
469        }
470
471        /**
472         * Return the fields that should <i>not</i> be allowed for binding.
473         * @return array of field names
474         */
475        public String[] getDisallowedFields() {
476                return this.disallowedFields;
477        }
478
479        /**
480         * Register fields that are required for each binding process.
481         * <p>If one of the specified fields is not contained in the list of
482         * incoming property values, a corresponding "missing field" error
483         * will be created, with error code "required" (by the default
484         * binding error processor).
485         * @param requiredFields array of field names
486         * @see #setBindingErrorProcessor
487         * @see DefaultBindingErrorProcessor#MISSING_FIELD_ERROR_CODE
488         */
489        public void setRequiredFields(String... requiredFields) {
490                this.requiredFields = PropertyAccessorUtils.canonicalPropertyNames(requiredFields);
491                if (logger.isDebugEnabled()) {
492                        logger.debug("DataBinder requires binding of required fields [" +
493                                        StringUtils.arrayToCommaDelimitedString(requiredFields) + "]");
494                }
495        }
496
497        /**
498         * Return the fields that are required for each binding process.
499         * @return array of field names
500         */
501        public String[] getRequiredFields() {
502                return this.requiredFields;
503        }
504
505        /**
506         * Set whether to extract the old field value when applying a
507         * property editor to a new value for a field.
508         * <p>Default is "true", exposing previous field values to custom editors.
509         * Turn this to "false" to avoid side effects caused by getters.
510         * @deprecated as of Spring 4.3.5, in favor of customizing this in
511         * {@link #createBeanPropertyBindingResult()} or
512         * {@link #createDirectFieldBindingResult()} itself
513         */
514        @Deprecated
515        public void setExtractOldValueForEditor(boolean extractOldValueForEditor) {
516                getPropertyAccessor().setExtractOldValueForEditor(extractOldValueForEditor);
517        }
518
519        /**
520         * Set the strategy to use for resolving errors into message codes.
521         * Applies the given strategy to the underlying errors holder.
522         * <p>Default is a DefaultMessageCodesResolver.
523         * @see BeanPropertyBindingResult#setMessageCodesResolver
524         * @see DefaultMessageCodesResolver
525         */
526        public void setMessageCodesResolver(MessageCodesResolver messageCodesResolver) {
527                Assert.state(this.messageCodesResolver == null, "DataBinder is already initialized with MessageCodesResolver");
528                this.messageCodesResolver = messageCodesResolver;
529                if (this.bindingResult != null && messageCodesResolver != null) {
530                        this.bindingResult.setMessageCodesResolver(messageCodesResolver);
531                }
532        }
533
534        /**
535         * Set the strategy to use for processing binding errors, that is,
536         * required field errors and {@code PropertyAccessException}s.
537         * <p>Default is a DefaultBindingErrorProcessor.
538         * @see DefaultBindingErrorProcessor
539         */
540        public void setBindingErrorProcessor(BindingErrorProcessor bindingErrorProcessor) {
541                Assert.notNull(bindingErrorProcessor, "BindingErrorProcessor must not be null");
542                this.bindingErrorProcessor = bindingErrorProcessor;
543        }
544
545        /**
546         * Return the strategy for processing binding errors.
547         */
548        public BindingErrorProcessor getBindingErrorProcessor() {
549                return this.bindingErrorProcessor;
550        }
551
552        /**
553         * Set the Validator to apply after each binding step.
554         * @see #addValidators(Validator...)
555         * @see #replaceValidators(Validator...)
556         */
557        public void setValidator(Validator validator) {
558                assertValidators(validator);
559                this.validators.clear();
560                this.validators.add(validator);
561        }
562
563        private void assertValidators(Validator... validators) {
564                Assert.notNull(validators, "Validators required");
565                Object target = getTarget();
566                for (Validator validator : validators) {
567                        if (validator != null && (target != null && !validator.supports(target.getClass()))) {
568                                throw new IllegalStateException("Invalid target for Validator [" + validator + "]: " + target);
569                        }
570                }
571        }
572
573        /**
574         * Add Validators to apply after each binding step.
575         * @see #setValidator(Validator)
576         * @see #replaceValidators(Validator...)
577         */
578        public void addValidators(Validator... validators) {
579                assertValidators(validators);
580                this.validators.addAll(Arrays.asList(validators));
581        }
582
583        /**
584         * Replace the Validators to apply after each binding step.
585         * @see #setValidator(Validator)
586         * @see #addValidators(Validator...)
587         */
588        public void replaceValidators(Validator... validators) {
589                assertValidators(validators);
590                this.validators.clear();
591                this.validators.addAll(Arrays.asList(validators));
592        }
593
594        /**
595         * Return the primary Validator to apply after each binding step, if any.
596         */
597        public Validator getValidator() {
598                return (this.validators.size() > 0 ? this.validators.get(0) : null);
599        }
600
601        /**
602         * Return the Validators to apply after data binding.
603         */
604        public List<Validator> getValidators() {
605                return Collections.unmodifiableList(this.validators);
606        }
607
608
609        //---------------------------------------------------------------------
610        // Implementation of PropertyEditorRegistry/TypeConverter interface
611        //---------------------------------------------------------------------
612
613        /**
614         * Specify a Spring 3.0 ConversionService to use for converting
615         * property values, as an alternative to JavaBeans PropertyEditors.
616         */
617        public void setConversionService(ConversionService conversionService) {
618                Assert.state(this.conversionService == null, "DataBinder is already initialized with ConversionService");
619                this.conversionService = conversionService;
620                if (this.bindingResult != null && conversionService != null) {
621                        this.bindingResult.initConversion(conversionService);
622                }
623        }
624
625        /**
626         * Return the associated ConversionService, if any.
627         */
628        public ConversionService getConversionService() {
629                return this.conversionService;
630        }
631
632        /**
633         * Add a custom formatter, applying it to all fields matching the
634         * {@link Formatter}-declared type.
635         * <p>Registers a corresponding {@link PropertyEditor} adapter underneath the covers.
636         * @param formatter the formatter to add, generically declared for a specific type
637         * @since 4.2
638         * @see #registerCustomEditor(Class, PropertyEditor)
639         */
640        public void addCustomFormatter(Formatter<?> formatter) {
641                FormatterPropertyEditorAdapter adapter = new FormatterPropertyEditorAdapter(formatter);
642                getPropertyEditorRegistry().registerCustomEditor(adapter.getFieldType(), adapter);
643        }
644
645        /**
646         * Add a custom formatter for the field type specified in {@link Formatter} class,
647         * applying it to the specified fields only, if any, or otherwise to all fields.
648         * <p>Registers a corresponding {@link PropertyEditor} adapter underneath the covers.
649         * @param formatter the formatter to add, generically declared for a specific type
650         * @param fields the fields to apply the formatter to, or none if to be applied to all
651         * @since 4.2
652         * @see #registerCustomEditor(Class, String, PropertyEditor)
653         */
654        public void addCustomFormatter(Formatter<?> formatter, String... fields) {
655                FormatterPropertyEditorAdapter adapter = new FormatterPropertyEditorAdapter(formatter);
656                Class<?> fieldType = adapter.getFieldType();
657                if (ObjectUtils.isEmpty(fields)) {
658                        getPropertyEditorRegistry().registerCustomEditor(fieldType, adapter);
659                }
660                else {
661                        for (String field : fields) {
662                                getPropertyEditorRegistry().registerCustomEditor(fieldType, field, adapter);
663                        }
664                }
665        }
666
667        /**
668         * Add a custom formatter, applying it to the specified field types only, if any,
669         * or otherwise to all fields matching the {@link Formatter}-declared type.
670         * <p>Registers a corresponding {@link PropertyEditor} adapter underneath the covers.
671         * @param formatter the formatter to add (does not need to generically declare a
672         * field type if field types are explicitly specified as parameters)
673         * @param fieldTypes the field types to apply the formatter to, or none if to be
674         * derived from the given {@link Formatter} implementation class
675         * @since 4.2
676         * @see #registerCustomEditor(Class, PropertyEditor)
677         */
678        public void addCustomFormatter(Formatter<?> formatter, Class<?>... fieldTypes) {
679                FormatterPropertyEditorAdapter adapter = new FormatterPropertyEditorAdapter(formatter);
680                if (ObjectUtils.isEmpty(fieldTypes)) {
681                        getPropertyEditorRegistry().registerCustomEditor(adapter.getFieldType(), adapter);
682                }
683                else {
684                        for (Class<?> fieldType : fieldTypes) {
685                                getPropertyEditorRegistry().registerCustomEditor(fieldType, adapter);
686                        }
687                }
688        }
689
690        @Override
691        public void registerCustomEditor(Class<?> requiredType, PropertyEditor propertyEditor) {
692                getPropertyEditorRegistry().registerCustomEditor(requiredType, propertyEditor);
693        }
694
695        @Override
696        public void registerCustomEditor(Class<?> requiredType, String field, PropertyEditor propertyEditor) {
697                getPropertyEditorRegistry().registerCustomEditor(requiredType, field, propertyEditor);
698        }
699
700        @Override
701        public PropertyEditor findCustomEditor(Class<?> requiredType, String propertyPath) {
702                return getPropertyEditorRegistry().findCustomEditor(requiredType, propertyPath);
703        }
704
705        @Override
706        public <T> T convertIfNecessary(Object value, Class<T> requiredType) throws TypeMismatchException {
707                return getTypeConverter().convertIfNecessary(value, requiredType);
708        }
709
710        @Override
711        public <T> T convertIfNecessary(Object value, Class<T> requiredType, MethodParameter methodParam)
712                        throws TypeMismatchException {
713
714                return getTypeConverter().convertIfNecessary(value, requiredType, methodParam);
715        }
716
717        @Override
718        public <T> T convertIfNecessary(Object value, Class<T> requiredType, Field field)
719                        throws TypeMismatchException {
720
721                return getTypeConverter().convertIfNecessary(value, requiredType, field);
722        }
723
724
725        /**
726         * Bind the given property values to this binder's target.
727         * <p>This call can create field errors, representing basic binding
728         * errors like a required field (code "required"), or type mismatch
729         * between value and bean property (code "typeMismatch").
730         * <p>Note that the given PropertyValues should be a throwaway instance:
731         * For efficiency, it will be modified to just contain allowed fields if it
732         * implements the MutablePropertyValues interface; else, an internal mutable
733         * copy will be created for this purpose. Pass in a copy of the PropertyValues
734         * if you want your original instance to stay unmodified in any case.
735         * @param pvs property values to bind
736         * @see #doBind(org.springframework.beans.MutablePropertyValues)
737         */
738        public void bind(PropertyValues pvs) {
739                MutablePropertyValues mpvs = (pvs instanceof MutablePropertyValues) ?
740                                (MutablePropertyValues) pvs : new MutablePropertyValues(pvs);
741                doBind(mpvs);
742        }
743
744        /**
745         * Actual implementation of the binding process, working with the
746         * passed-in MutablePropertyValues instance.
747         * @param mpvs the property values to bind,
748         * as MutablePropertyValues instance
749         * @see #checkAllowedFields
750         * @see #checkRequiredFields
751         * @see #applyPropertyValues
752         */
753        protected void doBind(MutablePropertyValues mpvs) {
754                checkAllowedFields(mpvs);
755                checkRequiredFields(mpvs);
756                applyPropertyValues(mpvs);
757        }
758
759        /**
760         * Check the given property values against the allowed fields,
761         * removing values for fields that are not allowed.
762         * @param mpvs the property values to be bound (can be modified)
763         * @see #getAllowedFields
764         * @see #isAllowed(String)
765         */
766        protected void checkAllowedFields(MutablePropertyValues mpvs) {
767                PropertyValue[] pvs = mpvs.getPropertyValues();
768                for (PropertyValue pv : pvs) {
769                        String field = PropertyAccessorUtils.canonicalPropertyName(pv.getName());
770                        if (!isAllowed(field)) {
771                                mpvs.removePropertyValue(pv);
772                                getBindingResult().recordSuppressedField(field);
773                                if (logger.isDebugEnabled()) {
774                                        logger.debug("Field [" + field + "] has been removed from PropertyValues " +
775                                                        "and will not be bound, because it has not been found in the list of allowed fields");
776                                }
777                        }
778                }
779        }
780
781        /**
782         * Return if the given field is allowed for binding.
783         * Invoked for each passed-in property value.
784         * <p>The default implementation checks for "xxx*", "*xxx" and "*xxx*" matches,
785         * as well as direct equality, in the specified lists of allowed fields and
786         * disallowed fields. A field matching a disallowed pattern will not be accepted
787         * even if it also happens to match a pattern in the allowed list.
788         * <p>Can be overridden in subclasses.
789         * @param field the field to check
790         * @return if the field is allowed
791         * @see #setAllowedFields
792         * @see #setDisallowedFields
793         * @see org.springframework.util.PatternMatchUtils#simpleMatch(String, String)
794         */
795        protected boolean isAllowed(String field) {
796                String[] allowed = getAllowedFields();
797                String[] disallowed = getDisallowedFields();
798                return ((ObjectUtils.isEmpty(allowed) || PatternMatchUtils.simpleMatch(allowed, field)) &&
799                                (ObjectUtils.isEmpty(disallowed) || !PatternMatchUtils.simpleMatch(disallowed, field)));
800        }
801
802        /**
803         * Check the given property values against the required fields,
804         * generating missing field errors where appropriate.
805         * @param mpvs the property values to be bound (can be modified)
806         * @see #getRequiredFields
807         * @see #getBindingErrorProcessor
808         * @see BindingErrorProcessor#processMissingFieldError
809         */
810        protected void checkRequiredFields(MutablePropertyValues mpvs) {
811                String[] requiredFields = getRequiredFields();
812                if (!ObjectUtils.isEmpty(requiredFields)) {
813                        Map<String, PropertyValue> propertyValues = new HashMap<String, PropertyValue>();
814                        PropertyValue[] pvs = mpvs.getPropertyValues();
815                        for (PropertyValue pv : pvs) {
816                                String canonicalName = PropertyAccessorUtils.canonicalPropertyName(pv.getName());
817                                propertyValues.put(canonicalName, pv);
818                        }
819                        for (String field : requiredFields) {
820                                PropertyValue pv = propertyValues.get(field);
821                                boolean empty = (pv == null || pv.getValue() == null);
822                                if (!empty) {
823                                        if (pv.getValue() instanceof String) {
824                                                empty = !StringUtils.hasText((String) pv.getValue());
825                                        }
826                                        else if (pv.getValue() instanceof String[]) {
827                                                String[] values = (String[]) pv.getValue();
828                                                empty = (values.length == 0 || !StringUtils.hasText(values[0]));
829                                        }
830                                }
831                                if (empty) {
832                                        // Use bind error processor to create FieldError.
833                                        getBindingErrorProcessor().processMissingFieldError(field, getInternalBindingResult());
834                                        // Remove property from property values to bind:
835                                        // It has already caused a field error with a rejected value.
836                                        if (pv != null) {
837                                                mpvs.removePropertyValue(pv);
838                                                propertyValues.remove(field);
839                                        }
840                                }
841                        }
842                }
843        }
844
845        /**
846         * Apply given property values to the target object.
847         * <p>Default implementation applies all of the supplied property
848         * values as bean property values. By default, unknown fields will
849         * be ignored.
850         * @param mpvs the property values to be bound (can be modified)
851         * @see #getTarget
852         * @see #getPropertyAccessor
853         * @see #isIgnoreUnknownFields
854         * @see #getBindingErrorProcessor
855         * @see BindingErrorProcessor#processPropertyAccessException
856         */
857        protected void applyPropertyValues(MutablePropertyValues mpvs) {
858                try {
859                        // Bind request parameters onto target object.
860                        getPropertyAccessor().setPropertyValues(mpvs, isIgnoreUnknownFields(), isIgnoreInvalidFields());
861                }
862                catch (PropertyBatchUpdateException ex) {
863                        // Use bind error processor to create FieldErrors.
864                        for (PropertyAccessException pae : ex.getPropertyAccessExceptions()) {
865                                getBindingErrorProcessor().processPropertyAccessException(pae, getInternalBindingResult());
866                        }
867                }
868        }
869
870
871        /**
872         * Invoke the specified Validators, if any.
873         * @see #setValidator(Validator)
874         * @see #getBindingResult()
875         */
876        public void validate() {
877                for (Validator validator : this.validators) {
878                        validator.validate(getTarget(), getBindingResult());
879                }
880        }
881
882        /**
883         * Invoke the specified Validators, if any, with the given validation hints.
884         * <p>Note: Validation hints may get ignored by the actual target Validator.
885         * @param validationHints one or more hint objects to be passed to a {@link SmartValidator}
886         * @see #setValidator(Validator)
887         * @see SmartValidator#validate(Object, Errors, Object...)
888         */
889        public void validate(Object... validationHints) {
890                for (Validator validator : getValidators()) {
891                        if (!ObjectUtils.isEmpty(validationHints) && validator instanceof SmartValidator) {
892                                ((SmartValidator) validator).validate(getTarget(), getBindingResult(), validationHints);
893                        }
894                        else if (validator != null) {
895                                validator.validate(getTarget(), getBindingResult());
896                        }
897                }
898        }
899
900        /**
901         * Close this DataBinder, which may result in throwing
902         * a BindException if it encountered any errors.
903         * @return the model Map, containing target object and Errors instance
904         * @throws BindException if there were any errors in the bind operation
905         * @see BindingResult#getModel()
906         */
907        public Map<?, ?> close() throws BindException {
908                if (getBindingResult().hasErrors()) {
909                        throw new BindException(getBindingResult());
910                }
911                return getBindingResult().getModel();
912        }
913
914
915        /**
916         * Inner class to avoid a hard dependency on Java 8.
917         */
918        @UsesJava8
919        private static class OptionalUnwrapper {
920
921                public static Object unwrap(Object optionalObject) {
922                        Optional<?> optional = (Optional<?>) optionalObject;
923                        if (!optional.isPresent()) {
924                                return null;
925                        }
926                        Object result = optional.get();
927                        Assert.isTrue(!(result instanceof Optional), "Multi-level Optional usage not supported");
928                        return result;
929                }
930        }
931
932}