簡體   English   中英

使用 java 中的自定義 object model 構造謂詞

[英]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");

我試過一個鏈接

java 中帶反射的謂詞

在此,我能夠推斷出屬性名稱,將 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM