public class DataBinder extends java.lang.Object implements PropertyEditorRegistry, TypeConverter
Note that there are potential security implications in failing to set an array
of allowed fields. In the case of HTTP form POST data for example, malicious clients
can attempt to subvert an application by supplying values for fields or properties
that do not exist on the form. In some cases this could lead to illegal data being
set on command objects or their nested objects. For this reason, it is
highly recommended to specify the allowedFields
property
on the DataBinder.
The binding results can be examined via the BindingResult
interface,
extending the Errors
interface: see the getBindingResult()
method.
Missing fields and property access exceptions will be converted to FieldErrors
,
collected in the Errors instance, using the following error codes:
By default, binding errors get resolved through the BindingErrorProcessor
strategy, processing for missing fields and property access exceptions: see the
setBindingErrorProcessor(org.springframework.validation.BindingErrorProcessor)
method. You can override the default strategy
if needed, for example to generate different error codes.
Custom validation errors can be added afterwards. You will typically want to resolve
such error codes into proper user-visible error messages; this can be achieved through
resolving each error via a MessageSource
, which is
able to resolve an ObjectError
/FieldError
through its
MessageSource.getMessage(org.springframework.context.MessageSourceResolvable, java.util.Locale)
method. The list of message codes can be customized through the MessageCodesResolver
strategy: see the setMessageCodesResolver(org.springframework.validation.MessageCodesResolver)
method. DefaultMessageCodesResolver
's
javadoc states details on the default resolution rules.
This generic data binder can be used in any kind of environment.
setAllowedFields(java.lang.String...)
,
setRequiredFields(java.lang.String...)
,
registerCustomEditor(java.lang.Class<?>, java.beans.PropertyEditor)
,
setMessageCodesResolver(org.springframework.validation.MessageCodesResolver)
,
setBindingErrorProcessor(org.springframework.validation.BindingErrorProcessor)
,
bind(org.springframework.beans.PropertyValues)
,
getBindingResult()
,
DefaultMessageCodesResolver
,
DefaultBindingErrorProcessor
,
MessageSource
Modifier and Type | Field and Description |
---|---|
private java.lang.String[] |
allowedFields |
private int |
autoGrowCollectionLimit |
private boolean |
autoGrowNestedPaths |
private BindingErrorProcessor |
bindingErrorProcessor |
private AbstractPropertyBindingResult |
bindingResult |
private ConversionService |
conversionService |
static int |
DEFAULT_AUTO_GROW_COLLECTION_LIMIT
Default limit for array and collection growing: 256.
|
static java.lang.String |
DEFAULT_OBJECT_NAME
Default object name used for binding: "target".
|
private java.lang.String[] |
disallowedFields |
private boolean |
ignoreInvalidFields |
private boolean |
ignoreUnknownFields |
protected static Log |
logger
We'll create a lot of DataBinder instances: Let's use a static logger.
|
private MessageCodesResolver |
messageCodesResolver |
private java.lang.String |
objectName |
private java.lang.String[] |
requiredFields |
private java.lang.Object |
target |
private SimpleTypeConverter |
typeConverter |
private java.util.List<Validator> |
validators |
Constructor and Description |
---|
DataBinder(java.lang.Object target)
Create a new DataBinder instance, with default object name.
|
DataBinder(java.lang.Object target,
java.lang.String objectName)
Create a new DataBinder instance.
|
Modifier and Type | Method and Description |
---|---|
void |
addCustomFormatter(Formatter<?> formatter)
Add a custom formatter, applying it to all fields matching the
Formatter -declared type. |
void |
addCustomFormatter(Formatter<?> formatter,
java.lang.Class<?>... fieldTypes)
Add a custom formatter, applying it to the specified field types only, if any,
or otherwise to all fields matching the
Formatter -declared type. |
void |
addCustomFormatter(Formatter<?> formatter,
java.lang.String... fields)
Add a custom formatter for the field type specified in
Formatter class,
applying it to the specified fields only, if any, or otherwise to all fields. |
void |
addValidators(Validator... validators)
Add Validators to apply after each binding step.
|
protected void |
applyPropertyValues(MutablePropertyValues mpvs)
Apply given property values to the target object.
|
private void |
assertValidators(Validator... validators) |
void |
bind(PropertyValues pvs)
Bind the given property values to this binder's target.
|
protected void |
checkAllowedFields(MutablePropertyValues mpvs)
Check the given property values against the allowed fields,
removing values for fields that are not allowed.
|
protected void |
checkRequiredFields(MutablePropertyValues mpvs)
Check the given property values against the required fields,
generating missing field errors where appropriate.
|
java.util.Map<?,?> |
close()
Close this DataBinder, which may result in throwing
a BindException if it encountered any errors.
|
<T> T |
convertIfNecessary(java.lang.Object value,
java.lang.Class<T> requiredType)
Convert the value to the required type (if necessary from a String).
|
<T> T |
convertIfNecessary(java.lang.Object value,
java.lang.Class<T> requiredType,
java.lang.reflect.Field field)
Convert the value to the required type (if necessary from a String).
|
<T> T |
convertIfNecessary(java.lang.Object value,
java.lang.Class<T> requiredType,
MethodParameter methodParam)
Convert the value to the required type (if necessary from a String).
|
<T> T |
convertIfNecessary(java.lang.Object value,
java.lang.Class<T> requiredType,
TypeDescriptor typeDescriptor)
Convert the value to the required type (if necessary from a String).
|
protected AbstractPropertyBindingResult |
createBeanPropertyBindingResult()
Create the
AbstractPropertyBindingResult instance using standard
JavaBean property access. |
protected AbstractPropertyBindingResult |
createDirectFieldBindingResult()
Create the
AbstractPropertyBindingResult instance using direct
field access. |
protected void |
doBind(MutablePropertyValues mpvs)
Actual implementation of the binding process, working with the
passed-in MutablePropertyValues instance.
|
java.beans.PropertyEditor |
findCustomEditor(java.lang.Class<?> requiredType,
java.lang.String propertyPath)
Find a custom property editor for the given type and property.
|
java.lang.String[] |
getAllowedFields()
Return the fields that should be allowed for binding.
|
int |
getAutoGrowCollectionLimit()
Return the current limit for array and collection auto-growing.
|
BindingErrorProcessor |
getBindingErrorProcessor()
Return the strategy for processing binding errors.
|
BindingResult |
getBindingResult()
Return the BindingResult instance created by this DataBinder.
|
ConversionService |
getConversionService()
Return the associated ConversionService, if any.
|
java.lang.String[] |
getDisallowedFields()
Return the fields that should not be allowed for binding.
|
protected AbstractPropertyBindingResult |
getInternalBindingResult()
Return the internal BindingResult held by this DataBinder,
as an AbstractPropertyBindingResult.
|
java.lang.String |
getObjectName()
Return the name of the bound object.
|
protected ConfigurablePropertyAccessor |
getPropertyAccessor()
Return the underlying PropertyAccessor of this binder's BindingResult.
|
protected PropertyEditorRegistry |
getPropertyEditorRegistry()
Return the underlying TypeConverter of this binder's BindingResult.
|
java.lang.String[] |
getRequiredFields()
Return the fields that are required for each binding process.
|
protected SimpleTypeConverter |
getSimpleTypeConverter()
Return this binder's underlying SimpleTypeConverter.
|
java.lang.Object |
getTarget()
Return the wrapped target object.
|
protected TypeConverter |
getTypeConverter()
Return the underlying TypeConverter of this binder's BindingResult.
|
Validator |
getValidator()
Return the primary Validator to apply after each binding step, if any.
|
java.util.List<Validator> |
getValidators()
Return the Validators to apply after data binding.
|
void |
initBeanPropertyAccess()
Initialize standard JavaBean property access for this DataBinder.
|
void |
initDirectFieldAccess()
Initialize direct field access for this DataBinder,
as alternative to the default bean property access.
|
protected boolean |
isAllowed(java.lang.String field)
Return if the given field is allowed for binding.
|
boolean |
isAutoGrowNestedPaths()
Return whether "auto-growing" of nested paths has been activated.
|
boolean |
isIgnoreInvalidFields()
Return whether to ignore invalid fields when binding.
|
boolean |
isIgnoreUnknownFields()
Return whether to ignore unknown fields when binding.
|
void |
registerCustomEditor(java.lang.Class<?> requiredType,
java.beans.PropertyEditor propertyEditor)
Register the given custom property editor for all properties of the given type.
|
void |
registerCustomEditor(java.lang.Class<?> requiredType,
java.lang.String field,
java.beans.PropertyEditor propertyEditor)
Register the given custom property editor for the given type and
property, or for all properties of the given type.
|
void |
replaceValidators(Validator... validators)
Replace the Validators to apply after each binding step.
|
void |
setAllowedFields(java.lang.String... allowedFields)
Register fields that should be allowed for binding.
|
void |
setAutoGrowCollectionLimit(int autoGrowCollectionLimit)
Specify the limit for array and collection auto-growing.
|
void |
setAutoGrowNestedPaths(boolean autoGrowNestedPaths)
Set whether this binder should attempt to "auto-grow" a nested path that contains a null value.
|
void |
setBindingErrorProcessor(BindingErrorProcessor bindingErrorProcessor)
Set the strategy to use for processing binding errors, that is,
required field errors and
PropertyAccessException s. |
void |
setConversionService(ConversionService conversionService)
Specify a Spring 3.0 ConversionService to use for converting
property values, as an alternative to JavaBeans PropertyEditors.
|
void |
setDisallowedFields(java.lang.String... disallowedFields)
Register fields that should not be allowed for binding.
|
void |
setIgnoreInvalidFields(boolean ignoreInvalidFields)
Set whether to ignore invalid fields, that is, whether to ignore bind
parameters that have corresponding fields in the target object which are
not accessible (for example because of null values in the nested path).
|
void |
setIgnoreUnknownFields(boolean ignoreUnknownFields)
Set whether to ignore unknown fields, that is, whether to ignore bind
parameters that do not have corresponding fields in the target object.
|
void |
setMessageCodesResolver(MessageCodesResolver messageCodesResolver)
Set the strategy to use for resolving errors into message codes.
|
void |
setRequiredFields(java.lang.String... requiredFields)
Register fields that are required for each binding process.
|
void |
setValidator(Validator validator)
Set the Validator to apply after each binding step.
|
void |
validate()
Invoke the specified Validators, if any.
|
void |
validate(java.lang.Object... validationHints)
Invoke the specified Validators, if any, with the given validation hints.
|
public static final java.lang.String DEFAULT_OBJECT_NAME
public static final int DEFAULT_AUTO_GROW_COLLECTION_LIMIT
protected static final Log logger
@Nullable private final java.lang.Object target
private final java.lang.String objectName
@Nullable private AbstractPropertyBindingResult bindingResult
@Nullable private SimpleTypeConverter typeConverter
private boolean ignoreUnknownFields
private boolean ignoreInvalidFields
private boolean autoGrowNestedPaths
private int autoGrowCollectionLimit
@Nullable private java.lang.String[] allowedFields
@Nullable private java.lang.String[] disallowedFields
@Nullable private java.lang.String[] requiredFields
@Nullable private ConversionService conversionService
@Nullable private MessageCodesResolver messageCodesResolver
private BindingErrorProcessor bindingErrorProcessor
private final java.util.List<Validator> validators
public DataBinder(@Nullable java.lang.Object target)
target
- the target object to bind onto (or null
if the binder is just used to convert a plain parameter value)DEFAULT_OBJECT_NAME
public DataBinder(@Nullable java.lang.Object target, java.lang.String objectName)
target
- the target object to bind onto (or null
if the binder is just used to convert a plain parameter value)objectName
- the name of the target object@Nullable public java.lang.Object getTarget()
public java.lang.String getObjectName()
public void setAutoGrowNestedPaths(boolean autoGrowNestedPaths)
If "true", a null path location will be populated with a default object value and traversed instead of resulting in an exception. This flag also enables auto-growth of collection elements when accessing an out-of-bounds index.
Default is "true" on a standard DataBinder. Note that since Spring 4.1 this feature is supported for bean property access (DataBinder's default mode) and field access.
public boolean isAutoGrowNestedPaths()
public void setAutoGrowCollectionLimit(int autoGrowCollectionLimit)
Default is 256, preventing OutOfMemoryErrors in case of large indexes. Raise this limit if your auto-growing needs are unusually high.
public int getAutoGrowCollectionLimit()
public void initBeanPropertyAccess()
This is the default; an explicit call just leads to eager initialization.
protected AbstractPropertyBindingResult createBeanPropertyBindingResult()
AbstractPropertyBindingResult
instance using standard
JavaBean property access.public void initDirectFieldAccess()
protected AbstractPropertyBindingResult createDirectFieldBindingResult()
AbstractPropertyBindingResult
instance using direct
field access.protected AbstractPropertyBindingResult getInternalBindingResult()
protected ConfigurablePropertyAccessor getPropertyAccessor()
protected SimpleTypeConverter getSimpleTypeConverter()
protected PropertyEditorRegistry getPropertyEditorRegistry()
protected TypeConverter getTypeConverter()
public BindingResult getBindingResult()
Errors
,
bind(org.springframework.beans.PropertyValues)
public void setIgnoreUnknownFields(boolean ignoreUnknownFields)
Default is "true". Turn this off to enforce that all bind parameters must have a matching field in the target object.
Note that this setting only applies to binding operations
on this DataBinder, not to retrieving values via its
BindingResult
.
public boolean isIgnoreUnknownFields()
public void setIgnoreInvalidFields(boolean ignoreInvalidFields)
Default is "false". Turn this on to ignore bind parameters for nested objects in non-existing parts of the target object graph.
Note that this setting only applies to binding operations
on this DataBinder, not to retrieving values via its
BindingResult
.
public boolean isIgnoreInvalidFields()
public void setAllowedFields(@Nullable java.lang.String... allowedFields)
Supports "xxx*", "*xxx" and "*xxx*" patterns. More sophisticated matching
can be implemented by overriding the isAllowed
method.
Alternatively, specify a list of disallowed fields.
allowedFields
- array of field namessetDisallowedFields(java.lang.String...)
,
isAllowed(String)
@Nullable public java.lang.String[] getAllowedFields()
public void setDisallowedFields(@Nullable java.lang.String... disallowedFields)
Supports "xxx*", "*xxx" and "*xxx*" patterns. More sophisticated matching
can be implemented by overriding the isAllowed
method.
Alternatively, specify a list of allowed fields.
disallowedFields
- array of field namessetAllowedFields(java.lang.String...)
,
isAllowed(String)
@Nullable public java.lang.String[] getDisallowedFields()
public void setRequiredFields(@Nullable java.lang.String... requiredFields)
If one of the specified fields is not contained in the list of incoming property values, a corresponding "missing field" error will be created, with error code "required" (by the default binding error processor).
requiredFields
- array of field namessetBindingErrorProcessor(org.springframework.validation.BindingErrorProcessor)
,
DefaultBindingErrorProcessor.MISSING_FIELD_ERROR_CODE
@Nullable public java.lang.String[] getRequiredFields()
public void setMessageCodesResolver(@Nullable MessageCodesResolver messageCodesResolver)
Default is a DefaultMessageCodesResolver.
public void setBindingErrorProcessor(BindingErrorProcessor bindingErrorProcessor)
PropertyAccessException
s.
Default is a DefaultBindingErrorProcessor.
DefaultBindingErrorProcessor
public BindingErrorProcessor getBindingErrorProcessor()
public void setValidator(@Nullable Validator validator)
private void assertValidators(Validator... validators)
public void addValidators(Validator... validators)
public void replaceValidators(Validator... validators)
@Nullable public Validator getValidator()
public java.util.List<Validator> getValidators()
public void setConversionService(@Nullable ConversionService conversionService)
@Nullable public ConversionService getConversionService()
public void addCustomFormatter(Formatter<?> formatter)
Formatter
-declared type.
Registers a corresponding PropertyEditor
adapter underneath the covers.
formatter
- the formatter to add, generically declared for a specific typeregisterCustomEditor(Class, PropertyEditor)
public void addCustomFormatter(Formatter<?> formatter, java.lang.String... fields)
Formatter
class,
applying it to the specified fields only, if any, or otherwise to all fields.
Registers a corresponding PropertyEditor
adapter underneath the covers.
formatter
- the formatter to add, generically declared for a specific typefields
- the fields to apply the formatter to, or none if to be applied to allregisterCustomEditor(Class, String, PropertyEditor)
public void addCustomFormatter(Formatter<?> formatter, java.lang.Class<?>... fieldTypes)
Formatter
-declared type.
Registers a corresponding PropertyEditor
adapter underneath the covers.
formatter
- the formatter to add (does not need to generically declare a
field type if field types are explicitly specified as parameters)fieldTypes
- the field types to apply the formatter to, or none if to be
derived from the given Formatter
implementation classregisterCustomEditor(Class, PropertyEditor)
public void registerCustomEditor(java.lang.Class<?> requiredType, java.beans.PropertyEditor propertyEditor)
PropertyEditorRegistry
registerCustomEditor
in interface PropertyEditorRegistry
requiredType
- the type of the propertypropertyEditor
- the editor to registerpublic void registerCustomEditor(@Nullable java.lang.Class<?> requiredType, @Nullable java.lang.String field, java.beans.PropertyEditor propertyEditor)
PropertyEditorRegistry
If the property path denotes an array or Collection property,
the editor will get applied either to the array/Collection itself
(the PropertyEditor
has to create an array or Collection value) or
to each element (the PropertyEditor
has to create the element type),
depending on the specified required type.
Note: Only one single registered custom editor per property path is supported. In the case of a Collection/array, do not register an editor for both the Collection/array and each element on the same property.
For example, if you wanted to register an editor for "items[n].quantity" (for all values n), you would use "items.quantity" as the value of the 'propertyPath' argument to this method.
registerCustomEditor
in interface PropertyEditorRegistry
requiredType
- the type of the property. This may be null
if a property is given but should be specified in any case, in particular in
case of a Collection - making clear whether the editor is supposed to apply
to the entire Collection itself or to each of its entries. So as a general rule:
Do not specify null
here in case of a Collection/array!field
- the path of the property (name or nested path), or
null
if registering an editor for all properties of the given typepropertyEditor
- editor to register@Nullable public java.beans.PropertyEditor findCustomEditor(@Nullable java.lang.Class<?> requiredType, @Nullable java.lang.String propertyPath)
PropertyEditorRegistry
findCustomEditor
in interface PropertyEditorRegistry
requiredType
- the type of the property (can be null
if a property
is given but should be specified in any case for consistency checking)propertyPath
- the path of the property (name or nested path), or
null
if looking for an editor for all properties of the given typenull
if none@Nullable public <T> T convertIfNecessary(@Nullable java.lang.Object value, @Nullable java.lang.Class<T> requiredType) throws TypeMismatchException
TypeConverter
Conversions from String to any type will typically use the setAsText
method of the PropertyEditor class, or a Spring Converter in a ConversionService.
convertIfNecessary
in interface TypeConverter
value
- the value to convertrequiredType
- the type we must convert to
(or null
if not known, for example in case of a collection element)TypeMismatchException
- if type conversion failedPropertyEditor.setAsText(String)
,
PropertyEditor.getValue()
,
ConversionService
,
Converter
@Nullable public <T> T convertIfNecessary(@Nullable java.lang.Object value, @Nullable java.lang.Class<T> requiredType, @Nullable MethodParameter methodParam) throws TypeMismatchException
TypeConverter
Conversions from String to any type will typically use the setAsText
method of the PropertyEditor class, or a Spring Converter in a ConversionService.
convertIfNecessary
in interface TypeConverter
value
- the value to convertrequiredType
- the type we must convert to
(or null
if not known, for example in case of a collection element)methodParam
- the method parameter that is the target of the conversion
(for analysis of generic types; may be null
)TypeMismatchException
- if type conversion failedPropertyEditor.setAsText(String)
,
PropertyEditor.getValue()
,
ConversionService
,
Converter
@Nullable public <T> T convertIfNecessary(@Nullable java.lang.Object value, @Nullable java.lang.Class<T> requiredType, @Nullable java.lang.reflect.Field field) throws TypeMismatchException
TypeConverter
Conversions from String to any type will typically use the setAsText
method of the PropertyEditor class, or a Spring Converter in a ConversionService.
convertIfNecessary
in interface TypeConverter
value
- the value to convertrequiredType
- the type we must convert to
(or null
if not known, for example in case of a collection element)field
- the reflective field that is the target of the conversion
(for analysis of generic types; may be null
)TypeMismatchException
- if type conversion failedPropertyEditor.setAsText(String)
,
PropertyEditor.getValue()
,
ConversionService
,
Converter
@Nullable public <T> T convertIfNecessary(@Nullable java.lang.Object value, @Nullable java.lang.Class<T> requiredType, @Nullable TypeDescriptor typeDescriptor) throws TypeMismatchException
TypeConverter
Conversions from String to any type will typically use the setAsText
method of the PropertyEditor class, or a Spring Converter in a ConversionService.
convertIfNecessary
in interface TypeConverter
value
- the value to convertrequiredType
- the type we must convert to
(or null
if not known, for example in case of a collection element)typeDescriptor
- the type descriptor to use (may be null
))TypeMismatchException
- if type conversion failedPropertyEditor.setAsText(String)
,
PropertyEditor.getValue()
,
ConversionService
,
Converter
public void bind(PropertyValues pvs)
This call can create field errors, representing basic binding errors like a required field (code "required"), or type mismatch between value and bean property (code "typeMismatch").
Note that the given PropertyValues should be a throwaway instance: For efficiency, it will be modified to just contain allowed fields if it implements the MutablePropertyValues interface; else, an internal mutable copy will be created for this purpose. Pass in a copy of the PropertyValues if you want your original instance to stay unmodified in any case.
pvs
- property values to binddoBind(org.springframework.beans.MutablePropertyValues)
protected void doBind(MutablePropertyValues mpvs)
mpvs
- the property values to bind,
as MutablePropertyValues instancecheckAllowedFields(org.springframework.beans.MutablePropertyValues)
,
checkRequiredFields(org.springframework.beans.MutablePropertyValues)
,
applyPropertyValues(org.springframework.beans.MutablePropertyValues)
protected void checkAllowedFields(MutablePropertyValues mpvs)
mpvs
- the property values to be bound (can be modified)getAllowedFields()
,
isAllowed(String)
protected boolean isAllowed(java.lang.String field)
The default implementation checks for "xxx*", "*xxx" and "*xxx*" matches, as well as direct equality, in the specified lists of allowed fields and disallowed fields. A field matching a disallowed pattern will not be accepted even if it also happens to match a pattern in the allowed list.
Can be overridden in subclasses.
field
- the field to checksetAllowedFields(java.lang.String...)
,
setDisallowedFields(java.lang.String...)
,
PatternMatchUtils.simpleMatch(String, String)
protected void checkRequiredFields(MutablePropertyValues mpvs)
mpvs
- the property values to be bound (can be modified)getRequiredFields()
,
getBindingErrorProcessor()
,
BindingErrorProcessor.processMissingFieldError(java.lang.String, org.springframework.validation.BindingResult)
protected void applyPropertyValues(MutablePropertyValues mpvs)
Default implementation applies all of the supplied property values as bean property values. By default, unknown fields will be ignored.
mpvs
- the property values to be bound (can be modified)getTarget()
,
getPropertyAccessor()
,
isIgnoreUnknownFields()
,
getBindingErrorProcessor()
,
BindingErrorProcessor.processPropertyAccessException(org.springframework.beans.PropertyAccessException, org.springframework.validation.BindingResult)
public void validate()
setValidator(Validator)
,
getBindingResult()
public void validate(java.lang.Object... validationHints)
Note: Validation hints may get ignored by the actual target Validator.
validationHints
- one or more hint objects to be passed to a SmartValidator
setValidator(Validator)
,
SmartValidator.validate(Object, Errors, Object...)
public java.util.Map<?,?> close() throws BindException
BindException
- if there were any errors in the bind operationBindingResult.getModel()