lambda方法引用获取字段属性
1、IGetter
import java.io.Serializable;
@FunctionalInterface
public interface IGetter<T> extends Serializable {
Object get(T source);
}
2、ISetter
import java.io.Serializable;
@FunctionalInterface
public interface ISetter<T, U> extends Serializable {
void set(T t, U u);
}
3、NjBeanUtils
import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import lombok.extern.slf4j.Slf4j;
/**
* @author : whp
* @describe :
* @date : 2022/6/29 9:53
*/
@Slf4j
public class NjBeanUtils extends BeanUtil {
/**
* list 列表之间的拷贝
* @param sources
* @param target
* @return
* @param <S>
* @param <T>
*/
public static <S, T> List<T> copyListProperties(List<S> sources, Supplier<T> target) {
if(CollUtil.isEmpty(sources)){
return null;
}
return copyListProperties(sources, target, null);
}
/**
* @author whp
* 使用场景:Entity、Bo、Vo层数据的复制,因为BeanUtils.copyProperties只能给目标对象的属性赋值,却不能在List集合下循环赋值,因此添加该方法
* 如:List<AdminEntity> 赋值到 List<AdminVo> ,List<AdminVo>中的 AdminVo 属性都会被赋予到值
* S: 数据源类 ,T: 目标类::new(eg: AdminVo::new)
*/
public static <S, T> List<T> copyListProperties(List<S> sources, Supplier<T> target, NjBeanUtilsCallBack<S, T> callBack) {
List<T> list = new ArrayList<>(sources.size());
for (S source : sources) {
T t = target.get();
copyProperties(source, t);
list.add(t);
if (callBack != null) {
// 回调
callBack.callBack(source, t);
}
}
return list;
}
/**
* 通过getter的方法引用获取字段名
*/
public static <T> String convertToFieldName(IGetter<T> fn) {
try {
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.error("无效的getter方法: " + methodName);
}
return toLowerCaseFirstOne(methodName.replace(prefix, ""));
} catch (Exception e) {
log.error("通过getter的方法引用获取字段名失败", e);
return null;
}
}
/**
* 通过setter的方法引用获取字段名
* @throws Exception
*/
public static <T, U> String convertToFieldName(ISetter<T, U> fn) {
try {
SerializedLambda lambda = getSerializedLambda(fn);
String methodName = lambda.getImplMethodName();
if (!methodName.startsWith("set")) {
log.error("无效的setter方法:" + methodName);
}
return toLowerCaseFirstOne(methodName.replace("set", ""));
} catch (Exception e) {
log.error("通过setter的方法引用获取字段名失败", e);
return null;
}
}
/**
* 关键在于这个方法
*/
private static SerializedLambda getSerializedLambda(Serializable fn) throws Exception {
Method method = fn.getClass().getDeclaredMethod("writeReplace");
method.setAccessible(Boolean.TRUE);
SerializedLambda lambda = (SerializedLambda) method.invoke(fn);
return lambda;
}
/**
* 字符串首字母转小写
*/
private static String toLowerCaseFirstOne(String field) {
if (Character.isLowerCase(field.charAt(0)))
return field;
else {
char firstOne = Character.toLowerCase(field.charAt(0));
String other = field.substring(1);
return new StringBuilder().append(firstOne).append(other).toString();
}
}
}
4、单元测试
public static void main(String[] args) {
System.out.println(NjBeanUtils.convertToFieldName(ShopIndex::getAddress));
System.out.println(NjBeanUtils.convertToFieldName(ShopIndex::getCityId));
System.out.println(NjBeanUtils.convertToFieldName(ShopIndex::setMartId));
System.out.println(NjBeanUtils.convertToFieldName(ShopIndex::setMartLocation));
}
5、运行结果
address
cityId
martId
martLocation
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
2020-08-15 windows下nacos的安装及Mysql持久化(单机部署)