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