【Spring源码分析】08-DataBinder

DataBinder实现了TypeConverter和PropertyEditorRegistry接口提供了类型转换功能,并且在设置值的同时做Validation。DataBinder有个重要的成员变量bindingResult是AbstractPropertyBindingResult,我们先分析他的用处。


Errors接口定义了存储与展示关于数据绑定和validation到指定对象的错误信息,AbstractErrors是一个抽象实现。对于错误信息存储的四个方法:

@Override
public void reject(String errorCode) {
   reject(errorCode, null, null);
}
@Override
public void reject(String errorCode, String defaultMessage) {
   reject(errorCode, null, defaultMessage);
}
@Override
public void rejectValue(@Nullable String field, String errorCode) {
   rejectValue(field, errorCode, null, null);
}
@Override
public void rejectValue(@Nullable String field, String errorCode, String defaultMessage) {
   rejectValue(field, errorCode, null, defaultMessage);
}

reject()和rejectValue()最终的实现方法被定义在了子类AbstractBindingResult,reject()方法用于为指定对象注册一个全局的错误信息,rejectValue()方法用于为一个对象的指定字段注册一个错误消息。

同样获取错误信息的方法也是给出了基本实现,最终的实现还是定义在了子类中。

@Override
@Nullable
public ObjectError getGlobalError() {
   List<ObjectError> globalErrors = getGlobalErrors();
   return (!globalErrors.isEmpty() ? globalErrors.get(0) : null);
}
@Override
public boolean hasFieldErrors() {
   return (getFieldErrorCount() > 0);
}
@Override
public int getFieldErrorCount() {
   return getFieldErrors().size();
}
@Override
@Nullable
public FieldError getFieldError() {
   List<FieldError> fieldErrors = getFieldErrors();
   return (!fieldErrors.isEmpty() ? fieldErrors.get(0) : null);
}
@Override
public boolean hasFieldErrors(String field) {
   return (getFieldErrorCount(field) > 0);
}
@Override
public int getFieldErrorCount(String field) {
   return getFieldErrors(field).size();
}
@Override
public List<FieldError> getFieldErrors(String field) {
   List<FieldError> fieldErrors = getFieldErrors();
   List<FieldError> result = new LinkedList<>();
   String fixedField = fixedField(field);
   for (FieldError error : fieldErrors) {
      if (isMatchingFieldError(fixedField, error)) {
         result.add(error);
      }
   }
   return Collections.unmodifiableList(result);
}
@Override
@Nullable
public FieldError getFieldError(String field) {
   List<FieldError> fieldErrors = getFieldErrors(field);
   return (!fieldErrors.isEmpty() ? fieldErrors.get(0) : null);
}
@Override
@Nullable
public Class<?> getFieldType(String field) {
   Object value = getFieldValue(field);
   return (value != null ? value.getClass() : null);
}

BindingResult接口扩展了Errors接口,额外定义了一些与数据绑定结果相关的方法,下面就看一看BindingResult与AbstractBindingResult共同的子类AbstractBindingResult。

主要成员变量:

private final String objectName;//为绑定对象起个名字,会作用域错误码和getModel()
private MessageCodesResolver messageCodesResolver = new DefaultMessageCodesResolver();//用于处理错误码,看下面解释
private final List<ObjectError> errors = new LinkedList<>();//存储数据绑定校验出现的错误
private final Map<String, Class<?>> fieldTypes = new HashMap<>(0);//字段名与字段类型
private final Map<String, Object> fieldValues = new HashMap<>(0);//字段名与字段值
private final Set<String> suppressedFields = new HashSet<>();//存储数据绑定不被允许的字段

reject()方法内部会将ObjectError或FieldError对象添加到成员变量errors中,这两个对象需要一个String[] codes,messageCodesResolver就是将reject方法参数errorCode转换为codes的作用。看一下他的文档描述。


下面是注册错误消息的实现:

@Override
public void reject(String errorCode, @Nullable Object[] errorArgs, @Nullable String defaultMessage) {
   addError(new ObjectError(getObjectName(), resolveMessageCodes(errorCode), errorArgs, defaultMessage));
}
@Override
public void rejectValue(@Nullable String field, String errorCode, @Nullable Object[] errorArgs,@Nullable String defaultMessage) {
   if ("".equals(getNestedPath()) && !StringUtils.hasLength(field)) {
      // We're at the top of the nested object hierarchy,
      // so the present level is not a field but rather the top object.
      // The best we can do is register a global error here...
      reject(errorCode, errorArgs, defaultMessage);
      return;
   }
   String fixedField = fixedField(field);
   Object newVal = getActualFieldValue(fixedField);
   FieldError fe = new FieldError(getObjectName(), fixedField, newVal, false, resolveMessageCodes(errorCode, field), errorArgs, defaultMessage);
   addError(fe);
}
@Override
public void addError(ObjectError error) {
   this.errors.add(error);
}

对于全局错误使用ObjectError,对于字段错误使用FieldError多了字段名字与字段值。

扫描二维码关注公众号,回复: 1880455 查看本文章

获取错误信息:

@Override
public List<ObjectError> getGlobalErrors() {
   List<ObjectError> result = new LinkedList<>();
   for (ObjectError objectError : this.errors) {
      if (!(objectError instanceof FieldError)) {
         result.add(objectError);
      }
   }
   return Collections.unmodifiableList(result);
}
@Override
@Nullable
public ObjectError getGlobalError() {
   for (ObjectError objectError : this.errors) {
      if (!(objectError instanceof FieldError)) {
         return objectError;
      }
   }
   return null;
}
@Override
public List<FieldError> getFieldErrors() {
   List<FieldError> result = new LinkedList<>();
   for (ObjectError objectError : this.errors) {
      if (objectError instanceof FieldError) {
         result.add((FieldError) objectError);
      }
   }
   return Collections.unmodifiableList(result);
}
@Override
@Nullable
public FieldError getFieldError() {
   for (ObjectError objectError : this.errors) {
      if (objectError instanceof FieldError) {
         return (FieldError) objectError;
      }
   }
   return null;
}
@Override
public List<FieldError> getFieldErrors(String field) {
   List<FieldError> result = new LinkedList<>();
   String fixedField = fixedField(field);
   for (ObjectError objectError : this.errors) {
      if (objectError instanceof FieldError && isMatchingFieldError(fixedField, (FieldError) objectError)) {
         result.add((FieldError) objectError);
      }
   }
   return Collections.unmodifiableList(result);
}
@Override
@Nullable
public FieldError getFieldError(String field) {
   String fixedField = fixedField(field);
   for (ObjectError objectError : this.errors) {
      if (objectError instanceof FieldError) {
         FieldError fieldError = (FieldError) objectError;
         if (isMatchingFieldError(fixedField, fieldError)) {
            return fieldError;
         }
      }
   }
   return null;
}

isMatchingFieldError()方法支持*号匹配。

protected boolean isMatchingFieldError(String field, FieldError fieldError) {
   if (field.equals(fieldError.getField())) {
      return true;
   }
   // Optimization: use charAt and regionMatches instead of endsWith and startsWith (SPR-11304)
   int endIndex = field.length() - 1;
   return (endIndex >= 0 && field.charAt(endIndex) == '*' &&
         (endIndex == 0 || field.regionMatches(0, fieldError.getField(), 0, endIndex)));
}
@Override
@Nullable
public Object getFieldValue(String field) {
   FieldError fieldError = getFieldError(field);
   // Use rejected value in case of error, current field value otherwise.
   if (fieldError != null) {
      Object value = fieldError.getRejectedValue();
      // Do not apply formatting on binding failures like type mismatches.
      return (fieldError.isBindingFailure() ? value : formatFieldValue(field, value));
   }
   else if (getTarget() != null) {
      Object value = getActualFieldValue(fixedField(field));
      return formatFieldValue(field, value);
   }
   else {
      return this.fieldValues.get(field);
   }
}
@Override
@Nullable
public Class<?> getFieldType(@Nullable String field) {
   if (getTarget() != null) {
      Object value = getActualFieldValue(fixedField(field));
      if (value != null) {
         return value.getClass();
      }
   }
   return this.fieldTypes.get(field);
}
@Override
@Nullable
public Object getRawFieldValue(String field) {
   return (getTarget() != null ? getActualFieldValue(fixedField(field)) : null);
}

上面方法中会用到子类实现方法getActualFieldValue(),formatFieldValue()。看一下在AbstractPropertyBindingResult中的实现:

@Override
@Nullable
public Class<?> getFieldType(@Nullable String field) {
   return (getTarget() != null ? getPropertyAccessor().getPropertyType(fixedField(field)) :
         super.getFieldType(field));
}
@Override
@Nullable
protected Object getActualFieldValue(String field) {
   return getPropertyAccessor().getPropertyValue(field);
}

@Override
protected Object formatFieldValue(String field, @Nullable Object value) {
   String fixedField = fixedField(field);
   // Try custom editor...
   PropertyEditor customEditor = getCustomEditor(fixedField);
   if (customEditor != null) {
      customEditor.setValue(value);
      String textValue = customEditor.getAsText();
      // If the PropertyEditor returned null, there is no appropriate
      // text representation for this value: only use it if non-null.
      if (textValue != null) {
         return textValue;
      }
   }
   if (this.conversionService != null) {
      // Try custom converter...
      TypeDescriptor fieldDesc = getPropertyAccessor().getPropertyTypeDescriptor(fixedField);
      TypeDescriptor strDesc = TypeDescriptor.valueOf(String.class);
      if (fieldDesc != null && this.conversionService.canConvert(fieldDesc, strDesc)) {
         return this.conversionService.convert(value, fieldDesc, strDesc);
      }
   }
   return value;
}

getPropertyAccessor()方法是一个抽象方法,由子类实现,看下在 BeanPropertyBindingResult中的实现:

@Override
public final ConfigurablePropertyAccessor getPropertyAccessor() {
   if (this.beanWrapper == null) {
      this.beanWrapper = createBeanWrapper();
      this.beanWrapper.setExtractOldValueForEditor(true);
      this.beanWrapper.setAutoGrowNestedPaths(this.autoGrowNestedPaths);
      this.beanWrapper.setAutoGrowCollectionLimit(this.autoGrowCollectionLimit);
   }
   return this.beanWrapper;
}
protected BeanWrapper createBeanWrapper() {
   if (this.target == null) {
      throw new IllegalStateException("Cannot access properties on null bean instance '" + getObjectName() + "'");
   }
   return PropertyAccessorFactory.forBeanPropertyAccess(this.target);
}

我们已经知道了BindingResult的体系机构了,下面正式说一下DataBinder了。

@Nullable
private final Object target;//需要数据绑定的对象
private final String objectName;//给对象起得名字默认target
@Nullable
private AbstractPropertyBindingResult bindingResult;//数据绑定后的结果
@Nullable
private SimpleTypeConverter typeConverter;//当target!=null时不会用到
private boolean ignoreUnknownFields = true;//忽略target不存在的属性,作用于PropertyAccessor的setPropertyValues()方法
private boolean ignoreInvalidFields = false;//忽略target不能访问的属性
private boolean autoGrowNestedPaths = true;//当嵌套属性为空时,是否可以实例化该属性
private int autoGrowCollectionLimit = DEFAULT_AUTO_GROW_COLLECTION_LIMIT;//对于集合类型容量的最大值
@Nullable
private String[] allowedFields;//允许数据绑定的资源
@Nullable
private String[] disallowedFields;//不允许的
@Nullable
private String[] requiredFields;//数据绑定必须存在的字段
@Nullable
private ConversionService conversionService;//为getPropertyAccessor().setConversionService(conversionService);
@Nullable
private MessageCodesResolver messageCodesResolver;//同bindingResult的
private BindingErrorProcessor bindingErrorProcessor = new DefaultBindingErrorProcessor();
private final List<Validator> validators = new ArrayList<>();//自定义数据校验器

BindingErrorProcessor接口定义了两个方法,用于处理不能存在的属性和将PropertyAccessException转换成一个FieldError。

public class DefaultBindingErrorProcessor implements BindingErrorProcessor {
   public static final String MISSING_FIELD_ERROR_CODE = "required";
   @Override
   public void processMissingFieldError(String missingField, BindingResult bindingResult) {
      // Create field error with code "required".
      String fixedField = bindingResult.getNestedPath() + missingField;
      String[] codes = bindingResult.resolveMessageCodes(MISSING_FIELD_ERROR_CODE, missingField);
      Object[] arguments = getArgumentsForBindError(bindingResult.getObjectName(), fixedField);
      FieldError error = new FieldError(bindingResult.getObjectName(), fixedField, "", true,
            codes, arguments, "Field '" + fixedField + "' is required");
      bindingResult.addError(error);
   }
   @Override
   public void processPropertyAccessException(PropertyAccessException ex, BindingResult bindingResult) {
      // Create field error with the exceptions's code, e.g. "typeMismatch".
      String field = ex.getPropertyName();
      Assert.state(field != null, "No field in exception");
      String[] codes = bindingResult.resolveMessageCodes(ex.getErrorCode(), field);
      Object[] arguments = getArgumentsForBindError(bindingResult.getObjectName(), field);
      Object rejectedValue = ex.getValue();
      if (ObjectUtils.isArray(rejectedValue)) {
         rejectedValue = StringUtils.arrayToCommaDelimitedString(ObjectUtils.toObjectArray(rejectedValue));
      }
      FieldError error = new FieldError(bindingResult.getObjectName(), field, rejectedValue, true,
            codes, arguments, ex.getLocalizedMessage());
      error.wrap(ex);
      bindingResult.addError(error);
   }
   protected Object[] getArgumentsForBindError(String objectName, String field) {
      String[] codes = new String[] {objectName + Errors.NESTED_PATH_SEPARATOR + field, field};
      return new Object[] {new DefaultMessageSourceResolvable(codes, field)};
   }
}

DataBinder实现了PropertyEditorRegistry接口需要实现接口的方法,采用了代理的方式,bindingResult是BeanPropertyBindingResult的实例,内部会持有一个BeanWrapperImpl,PropertyEditorRegistry接口的实现都是委托了BeanWrapperImpl。

@Override
public void registerCustomEditor(Class<?> requiredType, PropertyEditor propertyEditor) {
   getPropertyEditorRegistry().registerCustomEditor(requiredType, propertyEditor);
}
protected PropertyEditorRegistry getPropertyEditorRegistry() {
   if (getTarget() != null) {
      return getInternalBindingResult().getPropertyAccessor();
   }
   else {
      return getSimpleTypeConverter();
   }
}
protected AbstractPropertyBindingResult getInternalBindingResult() {
   if (this.bindingResult == null) {
      initBeanPropertyAccess();
   }
   return this.bindingResult;
}
public void initBeanPropertyAccess() {
   Assert.state(this.bindingResult == null,"DataBinder is already initialized - call initBeanPropertyAccess before other configuration methods");
   this.bindingResult = createBeanPropertyBindingResult();
}
protected AbstractPropertyBindingResult createBeanPropertyBindingResult() {
   BeanPropertyBindingResult result = new BeanPropertyBindingResult(getTarget(),getObjectName(), isAutoGrowNestedPaths(), getAutoGrowCollectionLimit());
   if (this.conversionService != null) {
      result.initConversion(this.conversionService);
   }
   if (this.messageCodesResolver != null) {
      result.setMessageCodesResolver(this.messageCodesResolver);
   }
   return result;
}

BeanPropertyBindingResult。

public class BeanPropertyBindingResult extends AbstractPropertyBindingResult implements Serializable {
   @Nullable
   private final Object target;
   private final boolean autoGrowNestedPaths;
   private final int autoGrowCollectionLimit;
   @Nullable
   private transient BeanWrapper beanWrapper;
   public BeanPropertyBindingResult(@Nullable Object target, String objectName) {
      this(target, objectName, true, Integer.MAX_VALUE);
   }
   public BeanPropertyBindingResult(@Nullable Object target, String objectName, boolean autoGrowNestedPaths, int autoGrowCollectionLimit) {
      super(objectName);
      this.target = target;
      this.autoGrowNestedPaths = autoGrowNestedPaths;
      this.autoGrowCollectionLimit = autoGrowCollectionLimit;
   }
   @Override
   @Nullable
   public final Object getTarget() {
      return this.target;
   }
   @Override
   public final ConfigurablePropertyAccessor getPropertyAccessor() {
      if (this.beanWrapper == null) {
         this.beanWrapper = createBeanWrapper();
         this.beanWrapper.setExtractOldValueForEditor(true);
         this.beanWrapper.setAutoGrowNestedPaths(this.autoGrowNestedPaths);
         this.beanWrapper.setAutoGrowCollectionLimit(this.autoGrowCollectionLimit);
      }
      return this.beanWrapper;
   }
   protected BeanWrapper createBeanWrapper() {
      if (this.target == null) {
         throw new IllegalStateException("Cannot access properties on null bean instance '" + getObjectName() + "'");
      }
      return PropertyAccessorFactory.forBeanPropertyAccess(this.target);
   }
}

核心方法:

public void bind(PropertyValues pvs) {
   MutablePropertyValues mpvs = (pvs instanceof MutablePropertyValues) ?
         (MutablePropertyValues) pvs : new MutablePropertyValues(pvs);
   doBind(mpvs);
}
protected void doBind(MutablePropertyValues mpvs) {
   checkAllowedFields(mpvs);
   checkRequiredFields(mpvs);
   applyPropertyValues(mpvs);
}

checkAllowedFields()方法不被允许的字段将移除,加入到bindingResult的suppressedFields中,这样就不会对该字段赋值并且记录下来。

protected void checkAllowedFields(MutablePropertyValues mpvs) {
   PropertyValue[] pvs = mpvs.getPropertyValues();
   for (PropertyValue pv : pvs) {
      String field = PropertyAccessorUtils.canonicalPropertyName(pv.getName());
      if (!isAllowed(field)) {
         mpvs.removePropertyValue(pv);
         getBindingResult().recordSuppressedField(field);
         if (logger.isDebugEnabled()) {
            logger.debug("Field [" + field + "] has been removed from PropertyValues " +
                  "and will not be bound, because it has not been found in the list of allowed fields");
         }
      }
   }
}
protected boolean isAllowed(String field) {
   String[] allowed = getAllowedFields();
   String[] disallowed = getDisallowedFields();
   return ((ObjectUtils.isEmpty(allowed) || PatternMatchUtils.simpleMatch(allowed, field)) &&
         (ObjectUtils.isEmpty(disallowed) || !PatternMatchUtils.simpleMatch(disallowed, field)));
}

checkRequiredFields()方法检查必须的字段是否存在或者可以访问,不满足则加入resultBinding中一个errorCode为required的FieldError对象。

protected void checkRequiredFields(MutablePropertyValues mpvs) {
   String[] requiredFields = getRequiredFields();
   if (!ObjectUtils.isEmpty(requiredFields)) {
      Map<String, PropertyValue> propertyValues = new HashMap<>();
      PropertyValue[] pvs = mpvs.getPropertyValues();
      for (PropertyValue pv : pvs) {
         String canonicalName = PropertyAccessorUtils.canonicalPropertyName(pv.getName());
         propertyValues.put(canonicalName, pv);
      }
      for (String field : requiredFields) {
         PropertyValue pv = propertyValues.get(field);
         boolean empty = (pv == null || pv.getValue() == null);
         if (!empty) {
            if (pv.getValue() instanceof String) {
               empty = !StringUtils.hasText((String) pv.getValue());
            }
            else if (pv.getValue() instanceof String[]) {
               String[] values = (String[]) pv.getValue();
               empty = (values.length == 0 || !StringUtils.hasText(values[0]));
            }
         }
         if (empty) {
            // Use bind error processor to create FieldError.
            getBindingErrorProcessor().processMissingFieldError(field, getInternalBindingResult());
            // Remove property from property values to bind:
            // It has already caused a field error with a rejected value.
            if (pv != null) {
               mpvs.removePropertyValue(pv);
               propertyValues.remove(field);
            }
         }
      }
   }
}

applyPropertyValues()方法使用resultBinding对象内的BeanWraperImpl对象完成属性的赋值操作,这个上篇讲过。需要注意的是,在PropertyAccessor的setPropertyValues()方法实现中AbstractPropertyAccessor给出了一个模板方法的实现:

public void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid)
      throws BeansException {
   List<PropertyAccessException> propertyAccessExceptions = null;
   List<PropertyValue> propertyValues = (pvs instanceof MutablePropertyValues ?
         ((MutablePropertyValues) pvs).getPropertyValueList() : Arrays.asList(pvs.getPropertyValues()));
   for (PropertyValue pv : propertyValues) {
      try {
         // This method may throw any BeansException, which won't be caught
         // here, if there is a critical failure such as no matching field.
         // We can attempt to deal only with less serious exceptions.
         setPropertyValue(pv);
      }
      catch (NotWritablePropertyException ex) {
         if (!ignoreUnknown) {
            throw ex;
         }
         // Otherwise, just ignore it and continue...
      }
      catch (NullValueInNestedPathException ex) {
         if (!ignoreInvalid) {
            throw ex;
         }
         // Otherwise, just ignore it and continue...
      }
      catch (PropertyAccessException ex) {
         if (propertyAccessExceptions == null) {
            propertyAccessExceptions = new LinkedList<>();
         }
         propertyAccessExceptions.add(ex);
      }
   }

   // If we encountered individual exceptions, throw the composite exception.
   if (propertyAccessExceptions != null) {
      PropertyAccessException[] paeArray =
            propertyAccessExceptions.toArray(new PropertyAccessException[propertyAccessExceptions.size()]);
      throw new PropertyBatchUpdateException(paeArray);
   }
}

setPropertyValue()方法运行的过程中可能会抛出各种PropertyAccessException,每种具体PropertyAccessException子类都有一个errorCode。抛出的这些异常会集中放入PropertyBatchUpdateException中打包发出。这是DataBinder的applyPropertyValues方法内会捕获这个异常,使用BindingErrorProcessor处理这些异常,转换为FieldError对象存储。

protected void applyPropertyValues(MutablePropertyValues mpvs) {
   try {
      // Bind request parameters onto target object.
      getPropertyAccessor().setPropertyValues(mpvs, isIgnoreUnknownFields(), isIgnoreInvalidFields());
   }
   catch (PropertyBatchUpdateException ex) {
      // Use bind error processor to create FieldErrors.
      for (PropertyAccessException pae : ex.getPropertyAccessExceptions()) {
         getBindingErrorProcessor().processPropertyAccessException(pae, getInternalBindingResult());
      }
   }
}

对象完成数据绑定后可以调用getBindingResult()方法,查看数据绑定后的各种数据。

WebDataBinder在doBind()方法中加入了两个检查方法用于处理参数带前缀“!”和“_”。

@Override
protected void doBind(MutablePropertyValues mpvs) {
   checkFieldDefaults(mpvs);//_
   checkFieldMarkers(mpvs);//!
   super.doBind(mpvs);
}
protected void checkFieldDefaults(MutablePropertyValues mpvs) {
   String fieldDefaultPrefix = getFieldDefaultPrefix();
   if (fieldDefaultPrefix != null) {
      PropertyValue[] pvArray = mpvs.getPropertyValues();
      for (PropertyValue pv : pvArray) {
         if (pv.getName().startsWith(fieldDefaultPrefix)) {
            String field = pv.getName().substring(fieldDefaultPrefix.length());
            if (getPropertyAccessor().isWritableProperty(field) && !mpvs.contains(field)) {
               mpvs.add(field, pv.getValue());
            }
            mpvs.removePropertyValue(pv);
         }
      }
   }
}
protected void checkFieldMarkers(MutablePropertyValues mpvs) {
   String fieldMarkerPrefix = getFieldMarkerPrefix();
   if (fieldMarkerPrefix != null) {
      PropertyValue[] pvArray = mpvs.getPropertyValues();
      for (PropertyValue pv : pvArray) {
         if (pv.getName().startsWith(fieldMarkerPrefix)) {
            String field = pv.getName().substring(fieldMarkerPrefix.length());
            if (getPropertyAccessor().isWritableProperty(field) && !mpvs.contains(field)) {
               Class<?> fieldType = getPropertyAccessor().getPropertyType(field);
               mpvs.add(field, getEmptyValue(field, fieldType));
            }
            mpvs.removePropertyValue(pv);
         }
      }
   }
}
@Nullable
protected Object getEmptyValue(String field, @Nullable Class<?> fieldType) {
   return (fieldType != null ? getEmptyValue(fieldType) : null);
}
@Nullable
public Object getEmptyValue(Class<?> fieldType) {
   try {
      if (boolean.class == fieldType || Boolean.class == fieldType) {
         // Special handling of boolean property.
         return Boolean.FALSE;
      }
      else if (fieldType.isArray()) {
         // Special handling of array property.
         return Array.newInstance(fieldType.getComponentType(), 0);
      }
      else if (Collection.class.isAssignableFrom(fieldType)) {
         return CollectionFactory.createCollection(fieldType, 0);
      }
      else if (Map.class.isAssignableFrom(fieldType)) {
         return CollectionFactory.createMap(fieldType, 0);
      }
   }
   catch (IllegalArgumentException ex) {
      if (logger.isDebugEnabled()) {
         logger.debug("Failed to create default value - falling back to null: " + ex.getMessage());
      }
   }
   // Default value: null.
   return null;
}

ServletRequestDataBinder将bind()方法的 ServletRequest转换成 MutablePropertyValues再由父类做数据绑定。

具体测试请看org.springframework.web.bind.ServletRequestDataBinderTests

Spring提供了一系列工厂类来创建对应的WebDataBinder对象:


顶级接口定义了创建一个WebDataBinder的方法。

public interface WebDataBinderFactory {
   /**
    * Create a {@link WebDataBinder} for the given object.
    * @param webRequest the current request
    * @param target the object to create a data binder for,
    * or {@code null} if creating a binder for a simple type
    * @param objectName the name of the target object
    * @return the created {@link WebDataBinder} instance, never null
    * @throws Exception raised if the creation and initialization of the data binder fails
    */
   WebDataBinder createBinder(NativeWebRequest webRequest, @Nullable Object target, String objectName) throws Exception;
}

关于WebDataBinderFactory的部分我们再介绍到RequestMappingHandlerAdapter的时候再介绍。

猜你喜欢

转载自blog.csdn.net/shenchaohao12321/article/details/80356890