最近想在项目中通过传递数据表字段(传递lambda 例如 AstAsset::getAssetNo )来查询字段值,而不是查询所有的值。Mybatis-plus 已有实现,通过queryWrapper.lambda() 的源码过一遍看看如果 将AstAsset::getAssetNo 转为asset_no。
1:
@Override
public Children eq(boolean condition, R column, Object val) {
return addCondition(condition, column, EQ, val);
}
2:
protected Children addCondition(boolean condition, R column, SqlKeyword sqlKeyword, Object val) {
return doIt(condition, () -> columnToString(column), sqlKeyword, () -> formatSql("{0}", val));
}
3:
@Override
protected String columnToString(SFunction<T, ?> column) {
return columnToString(column, true);
}
4:
protected String columnToString(SFunction<T, ?> column, boolean onlyColumn) {
return getColumn(LambdaUtils.resolve(column), onlyColumn);
}
5:
private String getColumn(SerializedLambda lambda, boolean onlyColumn) throws MybatisPlusException {
String fieldName = PropertyNamer.methodToProperty(lambda.getImplMethodName());
Class aClass = lambda.getInstantiatedMethodType();
if (!initColumnMap) {
columnMap = LambdaUtils.getColumnMap(aClass);
}
Assert.notNull(columnMap, "can not find lambda cache for this entity [%s]", aClass.getName());
ColumnCache columnCache = columnMap.get(LambdaUtils.formatKey(fieldName));
Assert.notNull(columnCache, "can not find lambda cache for this property [%s] of entity [%s]",
fieldName, aClass.getName());
return onlyColumn ? columnCache.getColumn() : columnCache.getColumnSelect();
}
最终的获取字段属性名称asset_no 就是通过String getColumn(SerializedLambda lambda, boolean onlyColumn) 方法。
SerializedLambda:这里是mybatis-plus的,其实还有java本身有SerializedLambda,功能大同小异,只是mybatis-plus的reslove加了缓存。
只要是函数式结果继承了Serializable接口即支持序列化,那么就可以获取到一个他的SerializedLambda实例,通过此实例可以容易访问到该函数式接口的信息:
if (!initColumnMap) {
columnMap = LambdaUtils.getColumnMap(aClass);
}
columnMap 存放了类属性名称和 @TableField(value = "report_date") 注解对应关系。
关于方法传递lambda,调用报错Non-static method cannot be referenced from a static context,需要加泛型,不能用 ? 或者 ? extends 等通配等
public static SerializedLambda resolve(SFunction lambda) ,没有<T,R> 也不行。