Lambda表达式获得泛型
Lambda表达式获得泛型
在使用mybatis-plus的时候会用到lambda表达式构建查询条件,例如:
LambdaQueryWrapper lambdaQueryWrapper = Wrappers.lambdaQuery()
.select(User::getId)
.eq(User::getId, 1);
List userList = list(lambdaQueryWrapper);
通过Function表达式获得泛型以及对应的字段,用起来很简洁方便,公司的项目需要封装一个公共组件需要实现类似的功能,于是翻看了mybatis-plus的源码加上一些博客找到了两种实现方式,记录一下,仅供参考。
公共的函数式接口
import java.io.Serializable;
/**
* 支持序列化的 Function
*
* @author miemie
* @since 2018-05-12
*/
@FunctionalInterface
public interface SFunction extends Serializable { // 必须继承 Serializable 接口
/**
* Applies this function to the given argument.
*
* @param t the function argument
* @return the function result
*/
R apply(T t);
}
公共的实体类
package com.bart.tests.jdk.lambda;
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
方式1
SFunction object = User::getName;
Class lambdaClass = object.getClass();
Method method = lambdaClass.getDeclaredMethod("writeReplace");
//writeReplace是私有方法,需要去掉私有属性
method.setAccessible(Boolean.TRUE);
//手动调用writeReplace()方法,返回一个SerializedLambda对象
java.lang.invoke.SerializedLambda lambda = (java.lang.invoke.SerializedLambda) method.invoke(object);
// 获得类名
String implClass = lambda.getImplClass();
System.out.println(implClass);//com/bart/tests/jdk/User
// 获得方法明
String implMethodName = lambda.getImplMethodName();
System.out.println(implMethodName);//getName
// 获得当前接口名
String functionalInterfaceClassName = lambda.getFunctionalInterfaceClass();
System.out.println(functionalInterfaceClassName);//com/bart/tests/jdk/SFunction
方式2
参考mybatis-plus实现方式:
源码参考位置:com.baomidou.mybatisplus.core.toolkit.LambdaUtils#resolve(com.baomidou.mybatisplus.core.toolkit.support.SFunction)
自定义的SerializedLambda类
import java.io.*; /** * 这个类是从 {@link java.lang.invoke.SerializedLambda} 里面 copy 过来的 * 字段信息完全一样 *
* 负责将一个支持序列的 Function 序列化为 SerializedLambda * * @author HCL * @since 2018/05/10 */ @SuppressWarnings("unused") public class SerializedLambda implements Serializable { private static final long serialVersionUID = 8025925345765570181L; private Class<?> capturingClass; private String functionalInterfaceClass; private String functionalInterfaceMethodName; private String functionalInterfaceMethodSignature; private String implClass; private String implMethodName; private String implMethodSignature; private int implMethodKind; private String instantiatedMethodType; private Object[] capturedArgs; /** * 获取接口 class * * @return 返回 class 名称 */ public String getFunctionalInterfaceClassName() { return normalName(functionalInterfaceClass); } /** * 获取实现的 class * * @return 实现类 */ public Class getImplClass() { try { return Class.forName(getImplClassName()); } catch (ClassNotFoundException e) { throw new IllegalStateException("找不到指定的class!请仅在明确确定会有 class 的时候,调用该方法", e); } } /** * 获取 class 的名称 * * @return 类名 */ public String getImplClassName() { return normalName(implClass); } /** * 获取实现者的方法名称 * * @return 方法名称 */ public String getImplMethodName() { return implMethodName; } /** * 正常化类名称,将类名称中的 / 替换为 . * * @param name 名称 * @return 正常的类名 */ private String normalName(String name) { return name.replace('/', '.'); } /** * @return 字符串形式 */ @Override public String toString() { return String.format("%s -> %s::%s", getFunctionalInterfaceClassName(), getImplClass().getSimpleName(), implMethodName); } }
获得Function
泛型信息:
SFunction object = User::getName;
if (!object.getClass().isSynthetic()) {
System.err.println("该方法仅能传入 lambda 表达式产生的合成类");
return;
}
// copy mybatis-plus代码实现 开始 ============
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(object);
oos.flush();
oos.close();
byte[] byteArray = baos.toByteArray();
ObjectInputStream objIn = new ObjectInputStream(new ByteArrayInputStream(byteArray)) {
@Override
protected Class<?> resolveClass(ObjectStreamClass objectStreamClass) throws IOException, ClassNotFoundException {
Class<?> clazz = super.resolveClass(objectStreamClass);
return clazz == java.lang.invoke.SerializedLambda.class ? SerializedLambda.class : clazz;
}
};
// copy mybatis-plus代码实现 结束 ============
SerializedLambda lambda = (SerializedLambda)objIn.readObject();
objIn.close();
Class implClass = lambda.getImplClass();
System.out.println(implClass);//class com.bart.tests.jdk.User
String implClassName = lambda.getImplClassName();
System.out.println(implClassName);//com.bart.tests.jdk.User
String implMethodName = lambda.getImplMethodName();
System.out.println(implMethodName);//getName
String functionalInterfaceClassName = lambda.getFunctionalInterfaceClassName();
System.out.println(functionalInterfaceClassName);//com.bart.tests.jdk.SFunction
参考资料
参考博客1
mybatis-plus