在使用tkmapper的example时候,我们经常会写如下代码:
@Override
public JobDefinitionsEntity queryJobDefinitionByAppIdAndName(Integer appId, String name) {
Weekend<JobDefinitionsEntity> weekend = new Weekend<>(JobDefinitionsEntity.class);
weekend.weekendCriteria().andEqualTo(JobDefinitionsEntity::getAppId, String.valueOf(appId))
.andEqualTo(JobDefinitionsEntity::getName, name);
return jobDefinitionsMapper.selectOneByExample(weekend);
}
很好奇,
`weekend.weekendCriteria().andEqualTo(JobDefinitionsEntity::getAppId, appId) 这个是如何通过Function获取到appId这个属性名称的.
查看tkmapper源码可以看到源码如下:
public WeekendCriteria<A, B> andEqualTo(Fn<A, B> fn, Object value) {
super.andEqualTo(Reflections.fnToFieldName(fn), value);
return this;
}
`Reflections.fnToFieldName` 核心是这个方法
public static String fnToFieldName(Fn fn) {
try {
Method method = fn.getClass().getDeclaredMethod("writeReplace");
method.setAccessible(Boolean.TRUE);
SerializedLambda serializedLambda = (SerializedLambda) method.invoke(fn);
String getter = serializedLambda.getImplMethodName();
if (GET_PATTERN.matcher(getter).matches()) {
getter = getter.substring(3);
} else if (IS_PATTERN.matcher(getter).matches()) {
getter = getter.substring(2);
}
return Introspector.decapitalize(getter);
} catch (ReflectiveOperationException e) {
throw new ReflectionOperationException(e);
}
}
其中Fn定义为:
public interface Fn<T, R> extends Function<T, R>, Serializable {
}
看到这里会有以下几个疑问点
为什么tkmapper要自己再定义一个Fn extends Function ?能不能直接使用Function
Method method = fn.getClass().getDeclaredMethod("writeReplace"); 这个`writeReplace` 又是什么鬼
SerializedLambda serializedLambda = (SerializedLambda) method.invoke(fn); 的SerializedLambda又是什么
下面将一一回答
首先是问题1,它的答案其实和问题2有关系
writeReplace 是 Java 序列化机制中的一个方法,用于在序列化对象时返回一个代理对象,以便在反序列化对象时恢复原始对象。它的定义如下:
private Object writeReplace() throws ObjectStreamException;
在 Reflections.fnToFieldName 方法中,fn 参数是一个函数式接口,它实现了 Serializable 接口。因此,可以使用 writeReplace 方法来获取序列化后的 Lambda 表达式。
这样问题1和问题2就解答了
问题3:
SerializedLambda 是 Java 8 引入的一个类,它用于存储序列化后的 Lambda 表达式的信息,以便在反序列化时重新构建 Lambda 表达式。
具体来说,当一个 Lambda 表达式被序列化时,它的信息会被存储在一个 SerializedLambda 对象中。SerializedLambda 类实现了 Serializable 接口,因此可以被序列化和反序列化。在反序列化时,SerializedLambda 对象会被用来构建 Lambda 表达式的实例。
SerializedLambda 类包含了 Lambda 表达式的信息,例如:
capturingClass:表示 Lambda 表达式所在的类;
functionalInterfaceClass:表示 Lambda 表达式实现的函数式接口的类型;
functionalInterfaceMethodName:表示函数式接口中唯一的抽象方法的名称;
functionalInterfaceMethodSignature:表示函数式接口中唯一的抽象方法的签名;
implClass:表示 Lambda 表达式实现的类;
implMethodName:表示 Lambda 表达式实现的方法的名称;
implMethodSignature:表示 Lambda 表达式实现的方法的签名;
instantiatedMethodType:表示 Lambda 表达式实例的方法类型。
通过这些信息,SerializedLambda 类可以在反序列化时重新构建 Lambda 表达式的实例,并调用相应的方法。
SerializedLambda 类一般不需要我们手动使用,它通常是在反序列化 Lambda 表达式时由 Java 序列化机制自动使用。在 Reflections.fnToFieldName 方法中,SerializedLambda 类被用来从序列化后的 Lambda 表达式中获取方法名称。具体来说,serializedLambda.getImplMethodName() 方法可以获取 Lambda 表达式实现的方法的名称,这个名称就是从中提取方法名称的关键。