美文网首页diboot
利用Lambda实现通过getter/setter方法引用拿到属

利用Lambda实现通过getter/setter方法引用拿到属

作者: 一个鸡蛋壳儿 | 来源:发表于2019-06-14 13:51 被阅读0次

    很多开发场景需要用到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. 定义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);
    }
    

    2. 定义getter/setter引用转换属性名的工具类

    public class BeanUtils {
        ...
        /**
         * 缓存类-Lambda的映射关系
         */
        private static Map<Class, SerializedLambda> CLASS_LAMDBA_CACHE = new ConcurrentHashMap<>();
    
        /***
         * 转换方法引用为属性名
         * @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 = CLASS_LAMDBA_CACHE.get(fn.getClass());
            if(lambda == null){
                try{//提取SerializedLambda并缓存
                    Method method = fn.getClass().getDeclaredMethod("writeReplace");
                    method.setAccessible(Boolean.TRUE);
                    lambda = (SerializedLambda) method.invoke(fn);
                    CLASS_LAMDBA_CACHE.put(fn.getClass(), lambda);
                }
                catch (Exception e){
                    log.error("获取SerializedLambda异常, class="+fn.getClass().getSimpleName(), e);
                }
            }
            return lambda;
        }
    }
    

    3. 开心的引用

    String ITEM_NAME = BeanUtils.convertToFieldName(User::getOrgName);
    

    Diboot - 简单高效的轻代码开发框架

    相关文章

      网友评论

        本文标题:利用Lambda实现通过getter/setter方法引用拿到属

        本文链接:https://www.haomeiwen.com/subject/qauufctx.html