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 2022-08-15 15:54  Ruthless  阅读(1037)  评论(0编辑  收藏  举报