[英]Construct a predicate using custom object model in java
我有一個 object model 如下所示
public class Filter {
public String field;
public ConditionalOperator operator;
public String value;
}
我有一個對象列表,例如List<Employees>
基於過濾器輸入,我想在屬性上構造謂詞並將其應用於員工列表。
例子:
Employees
FirstName
LastName
CreatedOn (Timestamp)
Status (FullTime/ parttime)
IsActive(True / False)
Filter conditions will be looking like
[
{ "field":"FirstName", "operator":"StartsWith", "value":"john"}
]
運營商就像
Contains
,StartsWith
,EndsWith
,Equals
我想構造像PredicateBuilder(fieldName, operator, value)
這樣的謂詞,這樣我就可以得到
Predicate<Employees> filter = e -> e.FirstName.StartsWith("john");
我試過一個鏈接
在此,我能夠推斷出屬性名稱,將 equals 方法應用於動態值,例如
Class<?> cls = Employees.class;
Class<?> noparams[] = {};
try {
Method method = cls.getDeclaredMethod("get" + filter.getField(), noparams);
Predicate<ExecutionReport> first = e -> {
try {
Object val = method.invoke(e);
System.out.println(val);
return method.invoke(e).toString().startsWith(filter.getField());
} catch (IllegalAccessException illegalAccessException) {
illegalAccessException.printStackTrace();
} catch (InvocationTargetException invocationTargetException) {
invocationTargetException.printStackTrace();
}
return false;
};
return first;
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
請指導我如何構建動態謂詞,我一直在搜索互聯網,但沒有運氣,我在 Java 中關於反射和謂詞的信息較少
讓我們從使用一些簡單的構建塊開始:
public enum ConditionalOperator implements BiPredicate<String, String> {
Contains((test, value) -> test.contains(value)),
StartsWith((test, value) -> test.startsWith(value)),
EndsWith((test, value) -> test.endsWith(value)),
Equals((test, value) -> test.equals(value));
private final BiPredicate<String, String> predicate;
ConditionalOperator(BiPredicate<String, String> predicate) {
this.predicate = predicate;
}
@Override
public boolean test(String test, String value) {
return predicate.test(test, value);
}
}
我冒昧地將它實現為enum
,不確定它在您的設計中是什么。
現在我們需要一個值提取器:
public static Function<Employee, String> getField(String name) {
try {
Method method = Employee.class.getMethod("get" + name);
if (method.getReturnType() != String.class) {
throw new IllegalArgumentException("Employee.get" + name + " does not return a String");
}
return e -> {
try {
return (String) method.invoke(e);
} catch (ReflectiveOperationException roe) {
// Unlikely to happen
throw new RuntimeException(roe);
}
}
} catch (ReflectiveOperationException roe) {
// getter does not exist, what now?
throw new IllegalArgumentException(roe);
}
}
最后,我們需要將所有內容鏈接在一起:
public static Predicate<Employee> buildPredicate(Filter f) {
Function<Employee, String> fieldGetter = getField(f.field());
ConditionalOperator op = f.operator();
String value = f.value();
return e -> op.test(fieldGetter.apply(e), value);
}
這目前僅適用於String
,但您可能可以對其進行調整 - 最簡單的方法是刪除對返回值的檢查,而不是將結果轉換為 String 調用.toString()
。
動態讀取字段的方面只是其中的一部分。 這是阻止您的實現完全基於 static 代碼的唯一原因。
這是一個將“比較”邏輯放入“運算符”枚舉本身的解決方案。
enum ConditionalOperator {
CONTAINS(String::contains),
STARTSWITH(String::startsWith),
ENDSWITH(String::endsWith),
EQUALS(String::equals);
private final BiPredicate<String, String> predicate;
private ConditionalOperator(BiPredicate<String, String> predicate) {
this.predicate = predicate;
}
public <T> Predicate<T> toPredicate(Function<T, String> getter,
String search) {
return object -> this.predicate.test(getter.apply(object), search);
}
}
toPredicate()
方法采用一個 getter,它將傳入的 object 轉換為字符串。
接下來是一個 function 方法,它在給定類型和字段名稱的情況下創建 getter:
private static <T> Function<T, String> fieldExtractor(Class<T> cls, String field){
return object -> {
try {
Field f = cls.getDeclaredField(field);
f.setAccessible(true);
return (String) f.get(object);
} catch (Exception e) {
//handle properly
throw new RuntimeException(e);
}
};
}
使用上述內容,您可以通過執行以下操作將Filter
object 轉換為謂詞:
Filter filter = <dynamic value>;
Predicate<Employee> filterPredicate = filter.getOperator()
.toPredicate(fieldExtractor(Employee.class, filter.getField()),
filter.getValue());
如果您認為合適,您甚至可能想要緩存fieldExtractor
的結果。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.