/*
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.validation;
import java.beans.PropertyEditor;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.ConfigurablePropertyAccessor;
import org.springframework.beans.PropertyAccessorUtils;
import org.springframework.beans.PropertyEditorRegistry;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.support.ConvertingPropertyEditorAdapter;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
Abstract base class for BindingResult
implementations that work with Spring's PropertyAccessor
mechanism. Pre-implements field access through delegation to the corresponding PropertyAccessor methods. Author: Juergen Hoeller See Also: Since: 2.0
/**
* Abstract base class for {@link BindingResult} implementations that work with
* Spring's {@link org.springframework.beans.PropertyAccessor} mechanism.
* Pre-implements field access through delegation to the corresponding
* PropertyAccessor methods.
*
* @author Juergen Hoeller
* @since 2.0
* @see #getPropertyAccessor()
* @see org.springframework.beans.PropertyAccessor
* @see org.springframework.beans.ConfigurablePropertyAccessor
*/
@SuppressWarnings("serial")
public abstract class AbstractPropertyBindingResult extends AbstractBindingResult {
@Nullable
private transient ConversionService conversionService;
Create a new AbstractPropertyBindingResult instance.
Params: - objectName – the name of the target object
See Also:
/**
* Create a new AbstractPropertyBindingResult instance.
* @param objectName the name of the target object
* @see DefaultMessageCodesResolver
*/
protected AbstractPropertyBindingResult(String objectName) {
super(objectName);
}
public void initConversion(ConversionService conversionService) {
Assert.notNull(conversionService, "ConversionService must not be null");
this.conversionService = conversionService;
if (getTarget() != null) {
getPropertyAccessor().setConversionService(conversionService);
}
}
Returns the underlying PropertyAccessor.
See Also: - getPropertyAccessor()
/**
* Returns the underlying PropertyAccessor.
* @see #getPropertyAccessor()
*/
@Override
public PropertyEditorRegistry getPropertyEditorRegistry() {
return (getTarget() != null ? getPropertyAccessor() : null);
}
Returns the canonical property name.
See Also: - canonicalPropertyName.canonicalPropertyName
/**
* Returns the canonical property name.
* @see org.springframework.beans.PropertyAccessorUtils#canonicalPropertyName
*/
@Override
protected String canonicalFieldName(String field) {
return PropertyAccessorUtils.canonicalPropertyName(field);
}
Determines the field type from the property type.
See Also: - getPropertyAccessor()
/**
* Determines the field type from the property type.
* @see #getPropertyAccessor()
*/
@Override
@Nullable
public Class<?> getFieldType(@Nullable String field) {
return (getTarget() != null ? getPropertyAccessor().getPropertyType(fixedField(field)) :
super.getFieldType(field));
}
Fetches the field value from the PropertyAccessor.
See Also: - getPropertyAccessor()
/**
* Fetches the field value from the PropertyAccessor.
* @see #getPropertyAccessor()
*/
@Override
@Nullable
protected Object getActualFieldValue(String field) {
return getPropertyAccessor().getPropertyValue(field);
}
Formats the field value based on registered PropertyEditors.
See Also: - getCustomEditor
/**
* Formats the field value based on registered PropertyEditors.
* @see #getCustomEditor
*/
@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;
}
Retrieve the custom PropertyEditor for the given field, if any.
Params: - fixedField – the fully qualified field name
Returns: the custom PropertyEditor, or null
/**
* Retrieve the custom PropertyEditor for the given field, if any.
* @param fixedField the fully qualified field name
* @return the custom PropertyEditor, or {@code null}
*/
@Nullable
protected PropertyEditor getCustomEditor(String fixedField) {
Class<?> targetType = getPropertyAccessor().getPropertyType(fixedField);
PropertyEditor editor = getPropertyAccessor().findCustomEditor(targetType, fixedField);
if (editor == null) {
editor = BeanUtils.findEditorByConvention(targetType);
}
return editor;
}
This implementation exposes a PropertyEditor adapter for a Formatter,
if applicable.
/**
* This implementation exposes a PropertyEditor adapter for a Formatter,
* if applicable.
*/
@Override
@Nullable
public PropertyEditor findEditor(@Nullable String field, @Nullable Class<?> valueType) {
Class<?> valueTypeForLookup = valueType;
if (valueTypeForLookup == null) {
valueTypeForLookup = getFieldType(field);
}
PropertyEditor editor = super.findEditor(field, valueTypeForLookup);
if (editor == null && this.conversionService != null) {
TypeDescriptor td = null;
if (field != null && getTarget() != null) {
TypeDescriptor ptd = getPropertyAccessor().getPropertyTypeDescriptor(fixedField(field));
if (ptd != null && (valueType == null || valueType.isAssignableFrom(ptd.getType()))) {
td = ptd;
}
}
if (td == null) {
td = TypeDescriptor.valueOf(valueTypeForLookup);
}
if (this.conversionService.canConvert(TypeDescriptor.valueOf(String.class), td)) {
editor = new ConvertingPropertyEditorAdapter(this.conversionService, td);
}
}
return editor;
}
Provide the PropertyAccessor to work with, according to the
concrete strategy of access.
Note that a PropertyAccessor used by a BindingResult should
always have its "extractOldValueForEditor" flag set to "true"
by default, since this is typically possible without side effects
for model objects that serve as data binding target.
See Also: - setExtractOldValueForEditor.setExtractOldValueForEditor
/**
* Provide the PropertyAccessor to work with, according to the
* concrete strategy of access.
* <p>Note that a PropertyAccessor used by a BindingResult should
* always have its "extractOldValueForEditor" flag set to "true"
* by default, since this is typically possible without side effects
* for model objects that serve as data binding target.
* @see ConfigurablePropertyAccessor#setExtractOldValueForEditor
*/
public abstract ConfigurablePropertyAccessor getPropertyAccessor();
}