I have a object model like the one given below
public class Filter {
public String field;
public ConditionalOperator operator;
public String value;
}
I have a list of objects like List<Employees>
Based on the Filter inputs, I want to construct the predicate on the property and apply that to the list of employees.
Example:
Employees
FirstName
LastName
CreatedOn (Timestamp)
Status (FullTime/ parttime)
IsActive(True / False)
Filter conditions will be looking like
[
{ "field":"FirstName", "operator":"StartsWith", "value":"john"}
]
The operators are like
Contains
,StartsWith
,EndsWith
,Equals
I would like to construct the predicate like PredicateBuilder(fieldName, operator, value)
so that I can get like
Predicate<Employees> filter = e -> e.FirstName.StartsWith("john");
I have tried the one link
Predicate with Reflection in java
In this, I was able to infer the propertyname, apply the equals method to the dynamic value like
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();
}
Please guide me on how to construct the dynamic predicates, I have been searching the internet but with no luck and i have less information on reflection and predicates in Java
Let's start by using some simple building blocks:
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);
}
}
I took the liberty to implement it as an enum
, not sure what it is in your design.
Now we need a value extractor:
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);
}
}
And last, we need to chain everything together:
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);
}
This only works for String
s for now, but you can probably adapt it - the easiest is to remove the the check for the return value and instead of casting the result to String call .toString()
on it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With