# 利用Lambda实现通过getter/setter方法引用拿到属性名
author: diboot team , publish date: 2019.06.04
很多开发场景需要用到Java Bean的属性名,直接写死属性名字符串的形式容易产生bug(属性名一旦变化,IDE不会告诉你你的字符串需要同步修改)。JDK8的Lambda可以通过方法引用简化代码,同样也可以通过getter/setter的方法引用拿到属性名,避免潜在的bug。
# 期望实现效果
// 传统方式:hard code写死属性名
// String ITEM_NAME = "orgName";
// 方法引用:替代hard code字符串,当属性名变化时IDE会同步提示,避免未同步产生bug
String ITEM_NAME = BeanUtils.convertToFieldName(User::getOrgName);
1
2
3
4
2
3
4
# 具体实现代码封装
# 1. 定义FunctionalInterface 接收方法引用
/**
* getter方法接口定义
*/
@FunctionalInterface
public interface IGetter<T> extends Serializable {
Object apply(T source);
}
/**
* setter方法接口定义
*/
@FunctionalInterface
public interface ISetter<T, U> extends Serializable {
void accept(T t, U u);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 2. 定义getter/setter引用转换属性名的工具类
public class BeanUtils {
...
/***
* 转换方法引用为属性名
* @param fn
* @return
*/
public static <T> String convertToFieldName(IGetter<T> fn) {
SerializedLambda lambda = getSerializedLambda(fn);
String methodName = lambda.getImplMethodName();
String prefix = null;
if(methodName.startsWith("get")){
prefix = "get";
}
else if(methodName.startsWith("is")){
prefix = "is";
}
if(prefix == null){
log.warn("无效的getter方法: "+methodName);
}
// 截取get/is之后的字符串并转换首字母为小写(S为diboot项目的字符串工具类,可自行实现)
return S.uncapFirst(S.substringAfter(methodName, prefix));
}
/***
* 转换setter方法引用为属性名
* @param fn
* @return
*/
public static <T,R> String convertToFieldName(ISetter<T,R> fn) {
SerializedLambda lambda = getSerializedLambda(fn);
String methodName = lambda.getImplMethodName();
if(!methodName.startsWith("set")){
log.warn("无效的setter方法: "+methodName);
}
// 截取set之后的字符串并转换首字母为小写(S为diboot项目的字符串工具类,可自行实现)
return S.uncapFirst(S.substringAfter(methodName, "set"));
}
/***
* 获取类对应的Lambda
* @param fn
* @return
*/
private static SerializedLambda getSerializedLambda(Serializable fn){
//先检查缓存中是否已存在
SerializedLambda lambda = null;
try{//提取SerializedLambda并缓存
Method method = fn.getClass().getDeclaredMethod("writeReplace");
method.setAccessible(Boolean.TRUE);
lambda = (SerializedLambda) method.invoke(fn);
}
catch (Exception e){
log.error("获取SerializedLambda异常, class="+fn.getClass().getSimpleName(), e);
}
return lambda;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# 3. 开心的引用
String ITEM_NAME = BeanUtils.convertToFieldName(User::getOrgName);
1
[Diboot - 简单高效的低代码开发框架][1] [1]: https://www.diboot.com