随笔 - 1357  文章 - 0  评论 - 1104  阅读 - 1941万

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

 

posted on   Ruthless  阅读(1133)  评论(0编辑  收藏  举报
编辑推荐:
· 从 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持久化(单机部署)
< 2025年3月 >
23 24 25 26 27 28 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 1 2 3 4 5

点击右上角即可分享
微信分享提示