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