java - 查询解析器构建 Predicate 以过滤内存中的 bean
问题描述
我正在寻找一个可以解释查询(例如在配置文件中定义)并从中构造一个 java.util.Predicate 的解析器,我可以用它来过滤一组 bean。
例如,我希望能够定义
name = "John*" AND age < 30 and address.city = "Frankfurt"
然后我想使用这个谓词来过滤类型的bean
class Person {
String getName() { ... }
int getAge() { ... }
Address getAddress() { ... }
}
class Address {
String getCity() { ... }
}
实际上它并不真的需要使用 Predicate 实例,我只是在寻找一个工具,它接受我的文本查询和 bean 集合并返回这些 bean 的过滤集合。
解决方案
你可以使用javax.script.ScriptEngine
:
public static void main(String[] args) {
try {
ScriptEngineManager factory = new ScriptEngineManager();
// create a JavaScript engine
ScriptEngine engine = factory.getEngineByName("JavaScript");
// evaluate JavaScript code from String
String expression
= "name == \"John\" && age < 30 && address.city == \"Frankfurt\"";
Person person = new Person("John", 25, new Address("Frankfurt"));
System.out.println(engine.eval(expression, new BeanBindings(person)));
} catch (ScriptException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static class Person {
String name;
int age;
Address address;
Person(String name, int age, Address address) {
this.name = name;
this.age = age;
this.address = address;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public Address getAddress() {
return address;
}
}
public static class Address {
private String city;
public Address(String city) {
this.city = city;
}
public String getCity() {
return city;
}
}
private static class BeanBindings implements Bindings {
private final Object bean;
public BeanBindings(Object bean) {
this.bean = bean;
}
@Override
public Object put(String name, Object value) {
return null;
}
@Override
public void putAll(Map<? extends String, ? extends Object> toMerge) {
}
@Override
public boolean containsKey(Object key) {
Method getter = getter((String)key);
return getter != null;
}
@Override
public Object get(Object key) {
Method getter = getter((String)key);
try {
return getter == null ? null : getter.invoke(bean);
} catch (IllegalAccessException | IllegalArgumentException
| InvocationTargetException ex) {
throw new RuntimeException(ex.getMessage());
}
}
@Override
public Object remove(Object key) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public int size() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public boolean isEmpty() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public boolean containsValue(Object value) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void clear() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public Set<String> keySet() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public Collection<Object> values() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public Set<Entry<String, Object>> entrySet() {
throw new UnsupportedOperationException("Not supported yet.");
}
private Method getter(String propName) {
if (propName == null || propName.length() == 0) {
throw new IllegalArgumentException("empty property name");
}
try {
String sfx = Character.toUpperCase(propName.charAt(0))
+ propName.substring(1);
return bean.getClass().getMethod(
"get" + sfx, new Class[0]);
} catch (NoSuchMethodException ex) {
return null;
} catch (SecurityException ex) {
throw new RuntimeException(ex.getMessage());
}
}
}
推荐阅读
- c# - NEST 的泛型类型无效
- bash - 用于更改 PDF 标题的 Bash 脚本
- javascript - 在onchange函数javascript中调用onchange函数
- cytoscape.js - Cytoscape cy png 创建空图像
- java - 当它的焦点设置为false时如何检测ListView中的复选框的点击
- oracle - FOPEN 不接受目录路径
- multithreading - 标量泄露:-2 标量泄露:多线程 perl 脚本中的 2 个警告
- angular - 修补 Angular Material 组件中的方法
- statistics - 对时间序列执行 T 检验
- c# - C# - 提取压缩文件的内容而不保存