相关类:

  • org.springframework.web.method.annotation.ModelAttributeMethodProcessor Line160 开始对*Controller里的方法的参数进行赋值
  • ServletModelAttributeMethodProcessor
  • org.springframework.core.convert.support.GenericConversionService#convert(java.lang.Object, org.springframework.core.convert.TypeDescriptor, org.springframework.core.convert.TypeDescriptor)
  • org.springframework.beans.TypeConverterDelegate#convertIfNecessary(java.lang.String, java.lang.Object, java.lang.Object, java.lang.Class, org.springframework.core.convert.TypeDescriptor)

定位到最后,发现WebConversionService或DefaultConversionService均能完成将一个字符串转成Long/Integer/Enum/String等功能。

附上代码:

import lombok.Data;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.boot.autoconfigure.web.format.WebConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.data.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class ConvertTests {
    private DefaultConversionService defaultConversionService = new DefaultConversionService();
    private WebConversionService webConversionService = new WebConversionService(null);

    @Test
    public void testConvertString() {
        String source = "abcd";
        String target = defaultConversionService.convert(source, String.class);
        Assert.assertEquals(source, target);
    }

    @Test
    public void testConvertInteger() {
        String source = "123456";
        Integer target = defaultConversionService.convert(source, Integer.class);
        Assert.assertEquals(Integer.valueOf(source), target);
    }

    @Test
    public void testConvertEnum() {
        String source = "NORMAL";
        Obj.Status target = defaultConversionService.convert(source, Obj.Status.class);
        Assert.assertEquals(Obj.Status.valueOf(source), target);
    }

    @Test
    public void testConvertMapToObj() throws IllegalAccessException {
        Obj obj = new Obj();
        Map<String, String> source = new HashMap<>();
        source.put("id", "123456");
        source.put("name", "abcd");
        source.put("status", "NORMAL");
        Set<Map.Entry<String, String>> entries = source.entrySet();
        for (Map.Entry<String, String> entry : entries) {
            String key = entry.getKey();
            String value = entry.getValue();
            Field requiredField = ReflectionUtils.findRequiredField(obj.getClass(), key);
            Object convert = webConversionService.convert(value, requiredField.getType());
            requiredField.setAccessible(true);
            requiredField.set(obj, convert);
        }
        Assert.assertNotNull(obj);
        Assert.assertEquals(obj.getId(), Long.valueOf(source.get("id")));
        Assert.assertEquals(obj.getName(), source.get("name"));
        Assert.assertEquals(obj.getStatus(), Obj.Status.valueOf(source.get("status")));
    }

    @Data
    private static class Obj {
        public enum Status {
            DRAFT("草稿"),
            NORMAL("正常");

            private final String value;

            Status(String value) {
                this.value = value;
            }

            public String getInfo() {
                return this.value;
            }
        }
        private Long id;
        private String name;
        private Status status;
    }
}