I'm using mybatis-plus's lambda chained query and it looks like this
Long uid = new LambdaQueryChainWrapper(baseMapeer)
.select(User::getUid)
.eq(User::getUsername, username)
.get();
I think it's so tedious that I have to write every class, and sometimes I needed to add caching operations, so I write an abstract class to simplify the operation, like this
// abstract service
public <R> T getEntityByUniqueColumn(SFunction<T, R> lambda, R value) {
// use mybatis-plus util
final String keyColumn = keyName();
// USE THIRD-PARTY LIBRARY REFLECTION UTIL
final String propertyName = reflectProperty(lambda);
// use mybatis-plus util
final String columnName = reflectColumn(propertyName);
return new QueryChainWrapper(baseMapper)
.select(keyColumn)
.eq(columnName, value)
.get();
}
// actual service
public Long getUid(String username) {
return getEntityByUniqueColumn(User::getUsername, username);
}
I'm using the 'de.cronn.reflection.util.PropertyUtils' method to get propertyName through get lambda function
private String reflectPropertyName(SFunction<T, ?> getXxxSFunc) {
if (getXxxSFunc == null) return null;
try {
return PropertyUtils.getPropertyName(entityClass, getXxxSFunc::apply);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Now the problem arises. PropertyUtils requires a lambda expression with a TypedPropertyGetter parameter, while my abstract method provides a lambda expression with an SFunction parameter.
The method signature of the former is V get(T t), and the method signature of the latter is V apply(T t). I tried to convert from SFunction to TypedPropertyGetter by using lambda::apply.
But I encountered an exception when I executed it. The reason is: PropertyUtils will eventually check whether the lambda method passed is call site specific. If it is, it throws an exception. This means that we cannot express lambda expressions by delegation (there are attributes inside), and we must pass this parameter by user-defined, such as User::getUsername.
// source-code
private static void assertHasNoDeclaredFields(Object lambda) {
if (hasDeclaredFields(lambda)) {
throw new IllegalArgumentException(lambda + " is call site specific");
}
}
private static boolean hasDeclaredFields(Object lambda) {
return lambda.getClass().getDeclaredFields().length > 0;
}
There are many methods of abstract classes in my project. I want to know how to convert this lambda expression into a zero-one type without delegation.
Aucun commentaire:
Enregistrer un commentaire