• Spring ConversionService 类型转换(一)Converter


    Spring ConversionService 类型转换(一)Converter

    Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html)

    Spring ConversionService 类型转换系列文章:

    1. Spring ConversionService 类型转换(一)Converter
    2. Spring ConversionService 类型转换(二)ConversionService

    JDK 提供的 PropertyEditor 只能将 String 类型转为 Object,如果要将一种 Object 类型转换成另一种 Object 类型就只能使用 Spring 提供的 ConversionService 了,这些类都位于 org.springframework.core.convert 包下。

    一、ConversionService 使用

    private ConversionService conversionService;
    @Before
    public void before() {
        conversionService = new DefaultConversionService();
    }
    
    @Test
    public void test() {
        ConversionService conversionService = new DefaultConversionService();
        Integer value = conversionService.convert("1", Integer.class);
        Assert.assertTrue(value == 1);
    }
    

    在 DefaultConversionService 组件中已经注册了 Spring 默认的觉转换器,可以分为以下几类:

    • Converter 一对一转换,把 S 类型转化成 T 类型,最常用的转换器
    • ConverterFactory 一对 N 转换
    • GenericConverter N 对 N 转换

    二、三种转换器

    三种转换器

    2.1 Converter(1:1)

    (1) 接口

    @FunctionalInterface
    public interface Converter<S, T> {
        T convert(S source);
    }
    

    Converter接口很简单,就是把 S 类型转化成 T 类型。我们看一下使用方法:

    (2) 测试

    @Test
    public void converterTest() {
        // ObjectToStringConverter
        Assert.assertEquals("false", conversionService.convert(false, String.class));
        
        // StringToBooleanConverter
        Assert.assertTrue(conversionService.convert("true", Boolean.class));
    }
    

    (3) ObjectToStringConverter 分析

    ObjectToStringConverter 和 StringToBooleanConverter 都是在 DefaultConversionService 中内置的。

    final class ObjectToStringConverter implements Converter<Object, String> {
        @Override
        public String convert(Object source) {
            return source.toString();
        }
    }
    

    2.2 ConverterFactory(1:N)

    (1) 接口

    public interface ConverterFactory<S, R> {
        <T extends R> Converter<S, T> getConverter(Class<T> targetType);
    }
    

    R 的子类都可以统一由这个 ConverterFactory 进行转换。

    (2) 测试

    // 测试 ConverterFactory StringToNumberConverterFactory
    @Test
    public void converterFactoryTest() {
        Assert.assertTrue(conversionService.convert("1.2", double.class) == 1.2d);
        Assert.assertTrue(conversionService.convert("1", int.class) == 1);
        Assert.assertTrue(conversionService.convert("0x10", byte.class) == 0x10);
    }
    

    这里用到了 StringToNumberConverterFactory 把 String 转化成了 Number 的各个子类型,代码其实很简单:

    (3) StringToNumberConverterFactory 分析

    final class StringToNumberConverterFactory implements ConverterFactory<String, Number> {
        @Override
        public <T extends Number> Converter<String, T> getConverter(Class<T> targetType) {
            return new StringToNumber<>(targetType);
        }
    
        private static final class StringToNumber<T extends Number> implements Converter<String, T> {
            private final Class<T> targetType;
            public StringToNumber(Class<T> targetType) {
                this.targetType = targetType;
            }
    
            @Override
            public T convert(String source) {
                if (source.isEmpty()) {
                    return null;
                }
                // String 类型转换成 Number
                return NumberUtils.parseNumber(source, this.targetType);
            }
        }
    }
    

    2.3 GenericConverter(N:N)

    (1) 接口

    public interface GenericConverter {
        // 可以转换的类型
        Set<ConvertiblePair> getConvertibleTypes();
    
        Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
    
        final class ConvertiblePair {
            private final Class<?> sourceType;
            private final Class<?> targetType;
        }
    }
    
    // 匹配 GenericConverter
    public interface ConditionalConverter {
        boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType);
    }
    
    public interface ConditionalGenericConverter extends GenericConverter, ConditionalConverter {
    }
    

    GenericConverter 是 N:N 的转化,支持转化的所有类型都写在了属性 Set 内。

    (2) 测试

    // 测试 GenericConverter CollectionToCollectionConverter
    @Test
    public void genericConverterTest() {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
        Set<String> set = (Set<String>) conversionService.convert(list,
                TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Integer.class)),
                TypeDescriptor.collection(Set.class, TypeDescriptor.valueOf(String.class)));
        // List<Integer> -> Set<String>
        Assert.assertEquals("1", set.toArray(new String[0])[0]);
    }
    

    这里用到了 CollectionToCollectionConverter

    (3) CollectionToCollectionConverter 分析

    final class CollectionToCollectionConverter implements ConditionalGenericConverter {
        private final ConversionService conversionService;
        public CollectionToCollectionConverter(ConversionService conversionService) {
            this.conversionService = conversionService;
        }
    
        @Override
        public Set<ConvertiblePair> getConvertibleTypes() {
            return Collections.singleton(new ConvertiblePair(Collection.class, Collection.class));
        }
    
        @Override
        public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
            return ConversionUtils.canConvertElements(
                    sourceType.getElementTypeDescriptor(), targetType.getElementTypeDescriptor(), this.conversionService);
        }
    
        @Override
        public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
            if (source == null) {
                return null;
            }
            Collection<?> sourceCollection = (Collection<?>) source;
    
            // 集合类型
            boolean copyRequired = !targetType.getType().isInstance(source);
            // 1. targetType 集合类型没变,不用转换
            if (!copyRequired && sourceCollection.isEmpty()) {
                return source;
            }
    
            // 集合元素类型
            TypeDescriptor elementDesc = targetType.getElementTypeDescriptor();
            // 2. targetType 集合元素没有指定类型,即 Object,且集合类型没变
            if (elementDesc == null && !copyRequired) {
                return source;
            }
    
            // 创建一个空集合
            Collection<Object> target = CollectionFactory.createCollection(targetType.getType(),
                    (elementDesc != null ? elementDesc.getType() : null), sourceCollection.size());
    
            // 3. targetType 集合元素没有指定类型,则元素不用转换类型
            if (elementDesc == null) {
                target.addAll(sourceCollection);
            // 4. conversionService 将 sourceElement 转换为 targetElement 类型
            } else {
                for (Object sourceElement : sourceCollection) {
                    Object targetElement = this.conversionService.convert(sourceElement,
                            sourceType.elementTypeDescriptor(sourceElement), elementDesc);
                    target.add(targetElement);
                    if (sourceElement != targetElement) {
                        copyRequired = true;
                    }
                }
            }
            return (copyRequired ? target : source);
        }
    }
    

    参考:

    1. 《Spring 学习记录 3 ConversionService》:https://www.cnblogs.com/abcwt112/p/7447435.html

    每天用心记录一点点。内容也许不重要,但习惯很重要!

  • 相关阅读:
    在博客园安了新家,开心哦!
    ViewState与Session的区别(转)
    什么是web.config .net配置文件介绍
    YUI Grid CSS的优雅设计(转)
    css reset
    Windows、(*)nux回忆录 作为架构师的你 值得拥有 O(∩_∩)O~
    .NET互联网网站架构(非原创)
    重构与设计解析(非原创)
    SQL Server2005索引简介
    mongodb相关
  • 原文地址:https://www.cnblogs.com/binarylei/p/10263581.html
Copyright © 2020-2023  润新知