0
点赞
收藏
分享

微信扫一扫

Spring类ResolvableType、BeanWrapper使用

gy2006_sw 2022-05-24 阅读 5

  在阅读Spring、SpringMVC 源码的时候经常看到这几个类,简单总结下这几个工具类的核心使用方法。

1. ResolvableType

  直译过来就是可解析类型。 实际是对java自带的Type 的一层包装,用于解析各种参数以及泛型、泛型实际类型等。Type 主要继承关系如下:

Spring类ResolvableType、BeanWrapper使用_spring

 主要类如下:

/**
* Type 表示类型,java 所有的原生类型、参数化类型、变量类型、原子类型等都是该类实现。其主要实现有:
* java.lang.Class 类
* java.lang.reflect.ParameterizedType 参数化类型
* java.lang.reflect.WildcardType WildcardType represents a wildcard type expression, such as {@code ?}, {@code ? extends Number}, or {@code ? super Integer}
* java.lang.reflect.TypeVariable List<T> 这样的类型
*/

   ResolvableType 提供了一些主要api, forClass 针对class, forField 针对属性,forMethodXXX针对方法参数和方法返回值。

1. 原生jdk 方法获取方式

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

public class PlainTest2 {

public static void main(String[] args) throws Exception {
/**
* Type 表示类型,java 所有的原生类型、参数化类型、变量类型、原子类型等都是该类实现。其主要实现有:
* java.lang.Class 类
* java.lang.reflect.ParameterizedType 参数化类型
* java.lang.reflect.WildcardType WildcardType represents a wildcard type expression, such as {@code ?}, {@code ? extends Number}, or {@code ? super Integer}
* java.lang.reflect.TypeVariable List<T> 这样的类型
*/

// 类
Type[] genericInterfaces = Wrapper.class.getGenericInterfaces();

// 属性
Field field = Wrapper.class.getDeclaredField("ids");
Type genericType = field.getGenericType();
Field field2 = Wrapper.class.getDeclaredField("names");
Type genericType2 = field2.getGenericType();
Field field3 = Wrapper.class.getDeclaredField("names2");
Type genericType3 = field3.getGenericType();

// 方法
Method method = PlainTest2.class.getMethod("test", List.class, Map.class, String.class, Wrapper.class, String[].class, int[].class);
// 获取方法参数
Type[] genericParameterTypes = method.getGenericParameterTypes();
// 获取返回值
Type genericReturnType = method.getGenericReturnType();

System.out.println(genericReturnType);
// 如果想获取实际类型,ParameterizedType 表示是一种参数化类型,也就是泛型. 返回实际类型的数组, 比如Map<String, Object> 就是两个Type
Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
System.out.println(actualTypeArguments[0]); // actualTypeArguments[0] 实际是个class 对象
// 获取其实际类型
Type rawType = ((ParameterizedType) genericReturnType).getRawType(); // List.class, rawType实际是个class 对象
System.out.println(rawType);
}

public static List<String> test(List<Integer> datas, Map<String, Object> map, String s, Wrapper wrapper, String[] strs, int[] ints) throws NoSuchMethodException {
return null;
}

private static class Wrapper<T> {

private String name;

private List<Integer> ids;

private List<? extends Number> names;

private List<T> names2;
}

}

结果如下:

控制台:

java.util.List<java.lang.String>
class java.lang.String
interface java.util.List

debug 各对象:

Spring类ResolvableType、BeanWrapper使用_java_02

 2. Spring 的 ResolvableType 使用方式

import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class PlainTest {

public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException {
/** ResolvableType 实际是对 java.lang.reflect.Type 类的包装,并且提供了访问下面方法。官方介绍如下:
* Encapsulates a Java {@link java.lang.reflect.Type}, providing access to
* {@link #getSuperType() supertypes}, {@link #getInterfaces() interfaces}, and
* {@link #getGeneric(int...) generic parameters} along with the ability to ultimately
* {@link #resolve() resolve} to a {@link java.lang.Class}.
*/

// 1. 类测试
ResolvableType resolvableType = ResolvableType.forClass(IInterface1.class);
// 获取接口
ResolvableType[] interfaces = resolvableType.getInterfaces();
// 获取泛型
ResolvableType[] generics = resolvableType.getGenerics();
ResolvableType generic = resolvableType.getGeneric(1);
// 获取父类
ResolvableType superType = resolvableType.getSuperType();

// 2. 属性测试
// 获取字段属性
ResolvableType field = ResolvableType.forField(IInterface1.class.getDeclaredField("CACHE"));
// 获取其父类 AbstractMap<List<String>, List<Integer>>
ResolvableType superType1 = field.getSuperType();
/* 将其类型转为map,
* 实际这样解析结果等价于 private Map<List<String>, List<Integer>> CACHE = new HashMap<>(); 的解析结果
* asMap 内部调用的 as(Map.class), 所以下面两个等价。 as 内部实际是获取其接口或者父类对象。 同理还有 asCollection() 方法, asCollection() 调用as(Collection.class)
*/
ResolvableType fieldMap1 = field.asMap();
ResolvableType fieldMap2 = field.as(Map.class);
// 获取泛型相关
Class<?> resolve = field.getGenerics()[0].resolve(); // List<String>
Class<?> resolve1 = field.getGenerics()[0].getGeneric(0).resolve(); // String
// 递归获取泛型, 可以理解为获取指定层级的泛型类型
Class<?> aClass = field.resolveGeneric(1, 0); // Integer (获取List<Integer>的Integer)

// 3. 方法测试
Method method = IInterface1.class.getMethod("generateList", List.class);
// forMethodParameter 方法获取方法相关参数。
// MethodParameter(method, paramIndex) 是将方法以及参数下标进行包装,下标意义: -1 获取方法返回值,0是第一个参数,1是第二个参数
MethodParameter methodParameter = new MethodParameter(method, 0);
ResolvableType resolvableType1 = ResolvableType.forMethodParameter(methodParameter);
// 获取方法返回值相关描述
ResolvableType returnType = ResolvableType.forMethodReturnType(method);
ResolvableType returnType1 = ResolvableType.forMethodParameter(new MethodParameter(method, -1));
}

private interface Interface1<T, E> {
List<T> generateList(List<E> e);
}

private interface Interface2<T, E> {
List<T> generateList2(List<E> e);
}

private static class IInterface1<T> implements Interface1<Integer, String>, Interface2<Integer, String> {

/**
* 模拟缓存 (这种写法实际是测试转换,实际一般会直接前面用Map 接参数)
*/
private HashMap<List<String>, List<Integer>> CACHE = new HashMap<>();

@Override
public List<Integer> generateList(List<String> e) {
List<Integer> integers = CACHE.get(e);
if (integers == null) {

}
return null;
}

@Override
public List<Integer> generateList2(List<String> e) {
return null;
}

public T getParam() {
return null;
}
}

}

各对象如下:

Spring类ResolvableType、BeanWrapper使用_java_03

 2. BeanWrapperImpl 使用

  在spring 整个生命周期还有一个重要的对象就是: BeanWrapperImpl, 从字面意思就可以看出来是一个Bean 包装类实现,继承关系如下:

Spring类ResolvableType、BeanWrapper使用_java_04

其核心功能有下面:

1.  BeanWrapper 接口功能: 获取其包装类型以及属性内省相关

2. PropertyAccessor 接口功能: 获取属性值以及修改属性值,支持嵌套对象属性获取以及设置值。

3. TypeConverter接口功能: 进行类型的转换功能, 主要是兼容不同类型的对象之间的转换。(个人理解转换器功能比属性编辑器更强大)

4. PropertyEditorRegistry 接口的功能,属性编辑器。PropertyEditor 是JDK的属性编辑器,主要提供将字符串转换为其他类型对象。

下面研究其简单使用:

1. 定义一些简单的对象:

import lombok.Data;

import java.util.List;
import java.util.Map;

@Data
public class User {

private List<String> likes;

private Address address;

private String username;

private int weight;

private Map<String, Object> feature;

}


import lombok.Data;

@Data
public class Address {

private String province;

private String city;
}

2. 测试类:

import com.google.common.collect.Lists;
import lombok.Data;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;

import java.beans.PropertyDescriptor;
import java.beans.PropertyEditorSupport;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

@Data
public class TestClient {

public static void main(String[] args) {
User user = getUser();
BeanWrapper beanWrapper = new BeanWrapperImpl(user);

// 获取其包装类型以及属性内省相关 (org.springframework.beans.BeanWrapper 相关方法)
Class<?> wrappedClass = beanWrapper.getWrappedClass();
Object wrappedInstance = beanWrapper.getWrappedInstance();
// 获取属性描述器,内省属性
PropertyDescriptor[] propertyDescriptors = beanWrapper.getPropertyDescriptors();
PropertyDescriptor addressPropertyDescriptor = beanWrapper.getPropertyDescriptor("address");

// 获取属性以及修改属性。 org.springframework.beans.PropertyAccessor 接口的方法
// 1. 获取属性
// 嵌套获取
Object address1 = beanWrapper.getPropertyValue("address");
Object city = beanWrapper.getPropertyValue("address.city");
// 获取集合属性
Object likes0 = beanWrapper.getPropertyValue("likes[0]");
// 获取map 属性
Object featureAge = beanWrapper.getPropertyValue("feature[age]");
Object featureAge2 = beanWrapper.getPropertyValue("feature['age']");
Object featureAge3 = beanWrapper.getPropertyValue("feature[\"age\"]");
// 2. 修改属性
// 修改普通属性, k-v 修改
beanWrapper.setPropertyValue("username", "修改后的");
beanWrapper.setPropertyValue("address.city", "修改后的city");
// 使用PropertyValue 进行修改
PropertyValue pro1 = new PropertyValue("address.city", "修改后的city2");
beanWrapper.setPropertyValue(pro1);
// 可以使用Map 进行修改
Map<String, Object> updateProperties = new LinkedHashMap<>();
updateProperties.put("feature[age]", 1001);
updateProperties.put("username2", "修改的username2 ");
updateProperties.put("weight", 2);
// beanWrapper.setPropertyValues(updateProperties);
// 使用map 内部调用的是: setPropertyValues(new MutablePropertyValues(map)); 等价于下面方法,默认后面两个参数都是false
/**
* 可以直接使用下面方法。
* 第二个参数标识 ignoreUnknown 忽略在Bean中找不到的属性, 默认为false, 因为username2 属性不存在,会抛异常 org.springframework.beans.NotWritablePropertyException: Invalid property 'username2' of bean xxx。 设为true 之后会跳过
* 第三个参数标识 ignoreInvalid 忽略找到,但是没有访问权限的值
*/
beanWrapper.setPropertyValues(new MutablePropertyValues(updateProperties), true, false);

// 转换器TypeConverter 用法
Integer integer = beanWrapper.convertIfNecessary("1122", Integer.class);

// 属性编辑器PropertyEditor 用法
beanWrapper.registerCustomEditor(int.class, new PropertyEditorSupport() {
@Override
public void setAsText(String text) throws IllegalArgumentException {
// 故意将年龄加1
this.setValue(Integer.valueOf(text) + 1);
}
});
beanWrapper.setPropertyValue("weight", "10"); // 11, 会采用自己的PropertyEditor 转换
System.out.println(user.getWeight());
}

private static User getUser() {
User user = new User();
Address address = new Address();
user.setAddress(address);
Map<String, Object> feature = new HashMap<>();
user.setFeature(feature);

address.setCity("beijing");
address.setProvince("china");
user.setLikes(Lists.newArrayList("篮球", "足球"));
user.setUsername("username");
feature.put("birthday", new Date());
feature.put("age", 46);

return user;
}
}

3. debug 查看对象结果:

Spring类ResolvableType、BeanWrapper使用_java_05


【当你用心写完每一篇博客之后,你会发现它比你用代码实现功能更有成就感!】




举报

相关推荐

0 条评论