在 java 中使用自定义对象模型构建谓词
Construct a predicate using custom object model in java
我有一个如下所示的对象模型
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");
我试过link
Predicate with Reflection in 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
s,但您可以对其进行调整 - 最简单的方法是删除 return 值的检查,而不是将结果转换为 String 调用.toString()
就可以了。
关于动态读取字段的方面只是其中的一部分。这是唯一阻止您的实现完全基于静态代码的因素。
这是一个将 "comparison" 逻辑放入 "operator" 枚举本身的解决方案。
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 将传入对象转换为字符串。
接下来是创建 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
对象转换为谓词:
Filter filter = <dynamic value>;
Predicate<Employee> filterPredicate = filter.getOperator()
.toPredicate(fieldExtractor(Employee.class, filter.getField()),
filter.getValue());
如果您认为合适,您甚至可能想要缓存 fieldExtractor
的结果。
我有一个如下所示的对象模型
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");
我试过link
Predicate with Reflection in 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
s,但您可以对其进行调整 - 最简单的方法是删除 return 值的检查,而不是将结果转换为 String 调用.toString()
就可以了。
关于动态读取字段的方面只是其中的一部分。这是唯一阻止您的实现完全基于静态代码的因素。
这是一个将 "comparison" 逻辑放入 "operator" 枚举本身的解决方案。
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 将传入对象转换为字符串。
接下来是创建 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
对象转换为谓词:
Filter filter = <dynamic value>;
Predicate<Employee> filterPredicate = filter.getOperator()
.toPredicate(fieldExtractor(Employee.class, filter.getField()),
filter.getValue());
如果您认为合适,您甚至可能想要缓存 fieldExtractor
的结果。