Spring源码解析之-TypeConverter、TypeConverterDelegate分析
程序员文章站
2022-05-04 11:43:24
目录一、介绍二、源码分析2.1 convertIfNecessary 方法解析2.2 findDefaultEditor 方法解析2.3 doConvertValue 方法解析2.3 convertToTypedArray方法解析2.3 convertToTypedCollection方法解析三、小结一、介绍TypeConverter 类主要是 负责类型转换,其实现类是 TypeConverterSupport,但是所有的具体实现都是在TypeConverterDelegate 里面完成的.二、源码分...
目录
一、介绍
TypeConverter 类主要是 负责类型转换,其实现类是 TypeConverterSupport,但是所有的具体实现都是在TypeConverterDelegate 里面完成的.
二、源码分析
TypeConverterDelegate 里面总共包含的方法如下:
这里主要分析一些主要的方法
2.1 convertIfNecessary 方法解析
public <T> T convertIfNecessary(@Nullable String propertyName, @Nullable Object oldValue, @Nullable Object newValue,
@Nullable Class<T> requiredType, @Nullable TypeDescriptor typeDescriptor) throws IllegalArgumentException {
// 根据requiredType 和 propertyName 获取对应的定制编辑器
PropertyEditor editor = this.propertyEditorRegistry.findCustomEditor(requiredType, propertyName);
ConversionFailedException conversionAttemptEx = null;
// 获取对应的conversionService
ConversionService conversionService = this.propertyEditorRegistry.getConversionService();
if (editor == null && conversionService != null && newValue != null && typeDescriptor != null) {
// 为newValue 创建一个类型描述器
TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(newValue);
// 判断是否能sourceTypeDesc 转换为需要的typeDescriptor,如果可以
//直接调用conversionService.convert 进行返回
if (conversionService.canConvert(sourceTypeDesc, typeDescriptor)) {
try {
return (T) conversionService.convert(newValue, sourceTypeDesc, typeDescriptor);
}
catch (ConversionFailedException ex) {
// fallback to default conversion logic below
conversionAttemptEx = ex;
}
}
}
Object convertedValue = newValue;
// 自定义editor 不为空 或者 对应的值 不是 需要的类型
if (editor != null || (requiredType != null && !ClassUtils.isAssignableValue(requiredType, convertedValue))) {
// 如果需要的类型是集合类型,并且值是String 类型(String⇒ 集合)
if (typeDescriptor != null && requiredType != null && Collection.class.isAssignableFrom(requiredType) &&
convertedValue instanceof String) {
// 获取集合里面元素的类型描述器
TypeDescriptor elementTypeDesc = typeDescriptor.getElementTypeDescriptor();
if (elementTypeDesc != null) {
// 获取对应的类型
Class<?> elementType = elementTypeDesc.getType();
if (Class.class == elementType || Enum.class.isAssignableFrom(elementType)) {
//将String字符串逗号分隔开,转换成字符串数组
convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
}
}
}
//如果自定义编辑器 为null,就根据requiredType 设置相对应的编辑器
if (editor == null) {
editor = findDefaultEditor(requiredType);
}
//对convertedValue 进行相关的转换
convertedValue = doConvertValue(oldValue, convertedValue, requiredType, editor);
}
boolean standardConversion = false;
if (requiredType != null) {
// 这里都是一些标准的类型转换 ,根据各种类型调用相应的方法
if (convertedValue != null) {
// 如果是Object类型,直接强制转换并返回
if (Object.class == requiredType) {
return (T) convertedValue;
}
else if (requiredType.isArray()) {
//如果需要的类型是枚举类型
if (convertedValue instanceof String && Enum.class.isAssignableFrom(requiredType.getComponentType())) {
// 先将 转换为 逗号分隔的String 数组
convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
}
// 转换为数组
return (T) convertToTypedArray(convertedValue, propertyName, requiredType.getComponentType());
}
else if (convertedValue instanceof Collection) {
//如果convertedValue 是集合类型 ,进行相关的转换
convertedValue = convertToTypedCollection(
(Collection<?>) convertedValue, propertyName, requiredType, typeDescriptor);
standardConversion = true;
}
else if (convertedValue instanceof Map) {
// 如果确定,将键和值转换为相应的目标类型
convertedValue = convertToTypedMap(
(Map<?, ?>) convertedValue, propertyName, requiredType, typeDescriptor);
standardConversion = true;
}
// 如果convertedValue 是数组类型,并且 长度为1 ,那就把get(0) 赋值给本身
if (convertedValue.getClass().isArray() && Array.getLength(convertedValue) == 1) {
convertedValue = Array.get(convertedValue, 0);
standardConversion = true;
}
// 如果需要的类型是 String ,并且convertedValue 的类型是基本类型或者装箱类型,那就直接toString 后强行转换
if (String.class == requiredType && ClassUtils.isPrimitiveOrWrapper(convertedValue.getClass())) {
// We can stringify any primitive value...
return (T) convertedValue.toString();
}
else if (convertedValue instanceof String && !requiredType.isInstance(convertedValue)) {
if (conversionAttemptEx == null && !requiredType.isInterface() && !requiredType.isEnum()) {
try {
Constructor<T> strCtor = requiredType.getConstructor(String.class);
return BeanUtils.instantiateClass(strCtor, convertedValue);
}
catch (NoSuchMethodException ex) {
// proceed with field lookup
if (logger.isTraceEnabled()) {
logger.trace("No String constructor found on type [" + requiredType.getName() + "]", ex);
}
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Construction via String failed for type [" + requiredType.getName() + "]", ex);
}
}
}
String trimmedValue = ((String) convertedValue).trim();
if (requiredType.isEnum() && trimmedValue.isEmpty()) {
// It's an empty enum identifier: reset the enum value to null.
return null;
}
convertedValue = attemptToConvertStringToEnum(requiredType, trimmedValue, convertedValue);
standardConversion = true;
}
else if (convertedValue instanceof Number && Number.class.isAssignableFrom(requiredType)) {
convertedValue = NumberUtils.convertNumberToTargetClass(
(Number) convertedValue, (Class<Number>) requiredType);
standardConversion = true;
}
}
else {
// convertedValue == null
if (requiredType == Optional.class) {
convertedValue = Optional.empty();
}
}
if (!ClassUtils.isAssignableValue(requiredType, convertedValue)) {
if (conversionAttemptEx != null) {
// Original exception from former ConversionService call above...
throw conversionAttemptEx;
}
else if (conversionService != null && typeDescriptor != null) {
// ConversionService not tried before, probably custom editor found
// but editor couldn't produce the required type...
TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(newValue);
if (conversionService.canConvert(sourceTypeDesc, typeDescriptor)) {
return (T) conversionService.convert(newValue, sourceTypeDesc, typeDescriptor);
}
}
// Definitely doesn't match: throw IllegalArgumentException/IllegalStateException
StringBuilder msg = new StringBuilder();
msg.append("Cannot convert value of type '").append(ClassUtils.getDescriptiveType(newValue));
msg.append("' to required type '").append(ClassUtils.getQualifiedName(requiredType)).append("'");
if (propertyName != null) {
msg.append(" for property '").append(propertyName).append("'");
}
if (editor != null) {
msg.append(": PropertyEditor [").append(editor.getClass().getName()).append(
"] returned inappropriate value of type '").append(
ClassUtils.getDescriptiveType(convertedValue)).append("'");
throw new IllegalArgumentException(msg.toString());
}
else {
msg.append(": no matching editors or conversion strategy found");
throw new IllegalStateException(msg.toString());
}
}
}
if (conversionAttemptEx != null) {
if (editor == null && !standardConversion && requiredType != null && Object.class != requiredType) {
throw conversionAttemptEx;
}
logger.debug("Original ConversionService attempt failed - ignored since " +
"PropertyEditor based conversion eventually succeeded", conversionAttemptEx);
}
return (T) convertedValue;
}
2.2 findDefaultEditor 方法解析
private PropertyEditor findDefaultEditor(@Nullable Class<?> requiredType) {
PropertyEditor editor = null;
if (requiredType != null) {
// No custom editor -> check BeanWrapperImpl's default editors.
editor = this.propertyEditorRegistry.getDefaultEditor(requiredType);
if (editor == null && String.class != requiredType) {
// No BeanWrapper default editor -> check standard JavaBean editor.
editor = BeanUtils.findEditorByConvention(requiredType);
}
}
return editor;
}
2.3 doConvertValue 方法解析
private Object doConvertValue(@Nullable Object oldValue, @Nullable Object newValue,
@Nullable Class<?> requiredType, @Nullable PropertyEditor editor) {
Object convertedValue = newValue;
// 如果编辑器不为null ,并且 转换值的类型不是 String
if (editor != null && !(convertedValue instanceof String)) {
// 调用setValue 方法
//如果使用标准的PropertyEditors 的话,那就返回的是完全一样的对象,
// 这里是调用专门的编辑器的setValue方法进行从非String 转到需要的类型上
try {
editor.setValue(convertedValue);
Object newConvertedValue = editor.getValue();
// 如果不一样,就说明进行了转换,需要将convertedValue 替换为转换后的值
if (newConvertedValue != convertedValue) {
convertedValue = newConvertedValue;
// 这里将editor 置空,editor 已经进行了正确的转换,不需要再将其用于setAsText 的调用
editor = null;
}
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("PropertyEditor [" + editor.getClass().getName() + "] does not support setValue call", ex);
}
// 这里没有抛出异常,而是继续运行下面的代码
}
}
Object returnValue = convertedValue;
// 如果convertedValue 是String[] 数组类型,而需要的类型不是数组类型
// 那就先将convertedValue 转换为 逗号分隔的String 值
if (requiredType != null && !requiredType.isArray() && convertedValue instanceof String[]) {
if (logger.isTraceEnabled()) {
logger.trace("Converting String array to comma-delimited String [" + convertedValue + "]");
}
// 将 String 数组 转换为 逗号分隔的String 值
convertedValue = StringUtils.arrayToCommaDelimitedString((String[]) convertedValue);
}
if (convertedValue instanceof String) {
if (editor != null) {
if (logger.isTraceEnabled()) {
logger.trace("Converting String to [" + requiredType + "] using property editor [" + editor + "]");
}
String newTextValue = (String) convertedValue;
// 调用 PropertyEditor 的setAsText
return doConvertTextValue(oldValue, newTextValue, editor);
}
// 如果requiredType 是String ,直接赋值并返回
else if (String.class == requiredType) {
returnValue = convertedValue;
}
}
return returnValue;
}
2.3 convertToTypedArray方法解析
private Object convertToTypedArray(Object input, @Nullable String propertyName, Class<?> componentType) {
// 如果input 是集合类型
if (input instanceof Collection) {
// 将集合元素转换为数组元素
Collection<?> coll = (Collection<?>) input;
Object result = Array.newInstance(componentType, coll.size());
int i = 0;
for (Iterator<?> it = coll.iterator(); it.hasNext(); i++) {
// 进行遍历,对逐个元素进行转换
Object value = convertIfNecessary(
buildIndexedPropertyName(propertyName, i), null, it.next(), componentType);
Array.set(result, i, value);
}
return result;
}
// 如果输入的数组类型
else if (input.getClass().isArray()) {
// 对数组里面的元素进行 逐个转换(可能类型一样就不要转换)
if (componentType.equals(input.getClass().getComponentType()) &&
!this.propertyEditorRegistry.hasCustomEditorForElement(componentType, propertyName)) {
return input;
}
int arrayLength = Array.getLength(input);
Object result = Array.newInstance(componentType, arrayLength);
for (int i = 0; i < arrayLength; i++) {
Object value = convertIfNecessary(
buildIndexedPropertyName(propertyName, i), null, Array.get(input, i), componentType);
Array.set(result, i, value);
}
return result;
}
else {
//输入input 既不是集合类型,也不是数组类型,但是要转为数组
// 就整个转化为一个元素的数组
Object result = Array.newInstance(componentType, 1);
Object value = convertIfNecessary(
buildIndexedPropertyName(propertyName, 0), null, input, componentType);
Array.set(result, 0, value);
return result;
}
}
2.3 convertToTypedCollection方法解析
private Collection<?> convertToTypedCollection(Collection<?> original, @Nullable String propertyName,
Class<?> requiredType, @Nullable TypeDescriptor typeDescriptor) {
// 如果requiredType 不是集合类型,直接返回
if (!Collection.class.isAssignableFrom(requiredType)) {
return original;
}
// 判断是否是 集合相近的,比如:List,set,ArrayList..
boolean approximable = CollectionFactory.isApproximableCollectionType(requiredType);
//不是集合相近的,并且也不能对requiredType复制-注入原始Collection
if (!approximable && !canCreateCopy(requiredType)) {
if (logger.isDebugEnabled()) {
logger.debug("Custom Collection type [" + original.getClass().getName() +
"] does not allow for creating a copy - injecting original Collection as-is");
}
return original;
}
boolean originalAllowed = requiredType.isInstance(original);
TypeDescriptor elementType = (typeDescriptor != null ? typeDescriptor.getElementTypeDescriptor() : null);
// 集合里面没有指定类型,并且original 就是 requiredType 类型,propertyEditorRegistry里面也没有对应的自定义编辑器,就直接返回
if (elementType == null && originalAllowed &&
!this.propertyEditorRegistry.hasCustomEditorForElement(null, propertyName)) {
return original;
}
Iterator<?> it;
try {
it = original.iterator();
}
catch (Throwable ex) {
if (logger.isDebugEnabled()) {
logger.debug("Cannot access Collection of type [" + original.getClass().getName() +
"] - injecting original Collection as-is: " + ex);
}
return original;
}
Collection<Object> convertedCopy;
try {
if (approximable) {
convertedCopy = CollectionFactory.createApproximateCollection(original, original.size());
}
else {
convertedCopy = (Collection<Object>)
ReflectionUtils.accessibleConstructor(requiredType).newInstance();
}
}
catch (Throwable ex) {
if (logger.isDebugEnabled()) {
logger.debug("Cannot create copy of Collection type [" + original.getClass().getName() +
"] - injecting original Collection as-is: " + ex);
}
return original;
}
int i = 0;
// 遍历,进行转换
for (; it.hasNext(); i++) {
Object element = it.next();
String indexedPropertyName = buildIndexedPropertyName(propertyName, i);
Object convertedElement = convertIfNecessary(indexedPropertyName, null, element,
(elementType != null ? elementType.getType() : null) , elementType);
try {
convertedCopy.add(convertedElement);
}
catch (Throwable ex) {
if (logger.isDebugEnabled()) {
logger.debug("Collection type [" + original.getClass().getName() +
"] seems to be read-only - injecting original Collection as-is: " + ex);
}
return original;
}
originalAllowed = originalAllowed && (element == convertedElement);
}
return (originalAllowed ? original : convertedCopy);
}
// 不是接口、不是抽象类、public 类型、有对应的构造方法
private boolean canCreateCopy(Class<?> requiredType) {
return (!requiredType.isInterface() && !Modifier.isAbstract(requiredType.getModifiers()) &&
Modifier.isPublic(requiredType.getModifiers()) && ClassUtils.hasConstructor(requiredType));
}
三、小结
这里面的方法都是类型转换相关的.
本文地址:https://blog.csdn.net/mamamalululu00000000/article/details/107304965
推荐阅读
-
Spring源码解密之默认标签的解析
-
Spring源码解密之自定义标签与解析
-
Spring源码解密之默认标签的解析
-
Spring源码解密之自定义标签与解析
-
Springboot源码分析之Spring循环依赖揭秘
-
Spring5源码解析4-refresh方法之invokeBeanFactoryPostProcessors
-
Spring源码解析之ConfigurableApplicationContext
-
SpringBoot 源码解析 (六)----- Spring Boot的核心能力 - 内置Servlet容器源码分析(Tomcat)
-
九、Spring之BeanFactory源码分析(一)
-
Spring源码分析之IoC容器初始化