使用SerializedLambda代替字符串硬编码
如果你用过mybatis-plus的话,那么你对下面的代码一定不会陌生:
public List<Board> getListByName() { LambdaQueryWrapper<Board> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(Board::getName, "test"); return list(queryWrapper); }
这时候我们肯能会有这种疑问:框架是如何通过方法引用来获取列名称的呢?来看看mybatis-plus列对应的泛型的定义吧
/** * 支持序列化的 Function * * @author miemie * @since 2018-05-12 */ @FunctionalInterface public interface SFunction<T, R> extends Function<T, R>, Serializable { }
SerializedLambda:
这里面函数式接口继承了Serializable接口,意思也就是说这个函数式接口是支持序列化的,那么序列化的函数式接口有啥特殊之处呢?SerializedLambda登场了,它是jdk1.8提供的一个新的类,凡是继承了Serializable的函数式接口的实例都可以获取一个属于它的SerializedLambda实例,并且通过它获取到方法的名称,根据我们标准的java bean的定义规则就可以通过方法名称来获取属性名称,属性名称也就是我们数据库中对应的列了。
我们通过一个示例来看看如果通过方法引用来获取对应的方法名称。
首先我们定义2个函数式接口:注意函数式接口一定要继承Serializable接口才能获取方法信息。
get函数是接口:
package com.bsx.test.lambda; import java.io.Serializable; @FunctionalInterface public interface IGetter<T> extends Serializable { Object get(T source); }
set函数式接口:
package com.bsx.test.lambda; import java.io.Serializable; @FunctionalInterface public interface ISetter<T, U> extends Serializable { void set(T t, U u); }
定义一个实体:Person
package com.bsx.test.entity; import lombok.Data; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @Data public class Person { private int id; private String name; public Person() { } public Person(int id, String name) { this.id = id; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
我们写一个根据函数式接口来获取他们对应的方法引用的工具类:
package com.bsx.test.lambda; import lombok.extern.slf4j.Slf4j; import java.io.Serializable; import java.lang.invoke.SerializedLambda; import java.lang.reflect.Method; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @Slf4j public class BeanUtils { 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 StringUtils.toLowerCaseFirstOne(methodName.replace(prefix, "")); } public static <T, U> String convertToFieldName(ISetter<T, U> fn) { SerializedLambda lambda = getSerializedLambda(fn); String methodName = lambda.getImplMethodName(); if(!methodName.startsWith("set")) { log.warn("无效的setter方法:" + methodName); } return StringUtils.toLowerCaseFirstOne(methodName.replace("set", "")); } /** * 关键在于这个方法 */ public static SerializedLambda getSerializedLambda(Serializable fn) { SerializedLambda lambda = CLASS_LAMDBA_CACHE.get(fn.getClass()); if(lambda == null) { try { 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) { e.printStackTrace(); } } return lambda; } }
测试一下上面的这个工具类:
@Test public void testLambdaSerializable() { String getName = BeanUtils.convertToFieldName(Person::getId); System.out.println(getName); String setName = BeanUtils.convertToFieldName(Person::setId); System.out.println(setName); }
id
name
参考文章:
https://blog.csdn.net/tengdazhang770960436/article/details/99960693

浙公网安备 33010602011771号