寻找 JEXL 过滤器功能
Looking for JEXL Filter feature
我知道,我可以在JEXL中做几件事,但在其中找不到Filter功能,这确实非常有用。
我该如何做
var x=[{a:11,b=5},{a:1,b=15},{a:12,b=25},{a:4,b=35},{a:7,b=45}];
return x[.a>10].b; // Which filters to {a:11,b=5} & {a:12,b=25}
// & hence returns [5,25]
首先你的语法是无效的 JEXL。我假设你的意思是:
var x = [{'a':11,'b':5}, {'a':1,'b':15}, {'a':12,'b':25}, {'a':4,'b':35}, {'a':7,'b':45}];
由于您可以在 JEXL 脚本中的任何对象上调用任何 Java 方法,因此您(至少理论上)可以完全访问 Java 流 API.
但是,流 API 不能直接从原始数组中获得,我们不能不费吹灰之力就调用 Arrays.stream(x);
。最简单的解决方法是创建一个集合:
var x = {{'a':11,'b':5}, {'a':1,'b':15}, {'a':12,'b':25}, {'a':4,'b':35}, {'a':7,'b':45}};
现在我们可以简单地调用 stream()
并从那里开始工作:
x.stream();
我们现在想要的是这样的:
x.stream().filter(function(m){m['a']>10});
不幸的是,JEXL 中的方法解析器将无法使用 JEXL 函数正确解析 Stream.filter(Predicate)
,因为它不知道如何将 JEXL 函数转换为 Predicate
。 JEXL 函数的类型为 org.apache.commons.jexl3.internal.Closure
.
因此,您至少需要做的是在 Java 中提供您自己的 Predicate
实现,然后在您的脚本中创建一个新实例:
public class MyCustomFilterPredicate implements Predicate<HashMap<String, Integer>> {
@Override
public boolean test(final HashMap<String, Integer> m)
{
return m.get("a") > 10;
}
}
然后您可以在 JEXL 脚本中创建一个新实例:
var filterPredicate = new('my.custom.filter.predicate.MyCustomFilterPredicate');
Stream.map(Function)
也是如此:
public class MyCustomMapFunction implements Function<HashMap<String, Integer>, Integer> {
@Override
public Integer apply(final HashMap<String, Integer> m)
{
return m.get("b");
}
}
然后在您的脚本中再次创建一个新实例:
var mapFunction = new('my.custom.map.function.MyCustomMapFunction');
您的整个脚本将如下所示:
var x = {{'a':11,'b':5}, {'a':1,'b':15}, {'a':12,'b':25}, {'a':4,'b':35}, {'a':7,'b':45}};
var filterPredicate = new('my.custom.filter.predicate.MyCustomFilterPredicate');
var mapFunction = new('my.custom.map.function.MyCustomMapFunction');
return x.stream().filter(filterPredicate).map(mapFunction).toArray();
当然,您可能已经注意到谓词和函数实现的可重用性相当有限。这就是为什么我建议创建包装 JEXL 闭包的实现:
public class MyCustomFilterPredicate implements Predicate<Object> {
private final Closure closure;
public MyCustomFilterPredicate(final Closure closure) {
this.closure = closure;
}
@Override
public boolean test(final Object o)
{
return (boolean) closure.execute(JexlEngine.getThreadContext(), o);
}
}
public class MyCustomMapFunction implements Function<Object, Object> {
private final Closure closure;
public MyCustomMapFunction(final Closure closure) {
this.closure = closure;
}
@Override
public Object apply(final Object o)
{
return closure.execute(JexlEngine.getThreadContext(), o);
}
}
现在您可以按如下方式更改脚本并以各种方式重用这些 Java 类:
var x = {{'a':11,'b':5}, {'a':1,'b':15}, {'a':12,'b':25}, {'a':4,'b':35}, {'a':7,'b':45}};
var filterPredicate = new('my.custom.filter.predicate.MyCustomFilterPredicate', function(m){m['a']>10});
var mapFunction = new('my.custom.map.function.MyCustomMapFunction', function(m){m['b']});
return x.stream().filter(filterPredicate).map(mapFunction).toArray();
我知道,我可以在JEXL中做几件事,但在其中找不到Filter功能,这确实非常有用。
我该如何做
var x=[{a:11,b=5},{a:1,b=15},{a:12,b=25},{a:4,b=35},{a:7,b=45}];
return x[.a>10].b; // Which filters to {a:11,b=5} & {a:12,b=25}
// & hence returns [5,25]
首先你的语法是无效的 JEXL。我假设你的意思是:
var x = [{'a':11,'b':5}, {'a':1,'b':15}, {'a':12,'b':25}, {'a':4,'b':35}, {'a':7,'b':45}];
由于您可以在 JEXL 脚本中的任何对象上调用任何 Java 方法,因此您(至少理论上)可以完全访问 Java 流 API.
但是,流 API 不能直接从原始数组中获得,我们不能不费吹灰之力就调用 Arrays.stream(x);
。最简单的解决方法是创建一个集合:
var x = {{'a':11,'b':5}, {'a':1,'b':15}, {'a':12,'b':25}, {'a':4,'b':35}, {'a':7,'b':45}};
现在我们可以简单地调用 stream()
并从那里开始工作:
x.stream();
我们现在想要的是这样的:
x.stream().filter(function(m){m['a']>10});
不幸的是,JEXL 中的方法解析器将无法使用 JEXL 函数正确解析 Stream.filter(Predicate)
,因为它不知道如何将 JEXL 函数转换为 Predicate
。 JEXL 函数的类型为 org.apache.commons.jexl3.internal.Closure
.
因此,您至少需要做的是在 Java 中提供您自己的 Predicate
实现,然后在您的脚本中创建一个新实例:
public class MyCustomFilterPredicate implements Predicate<HashMap<String, Integer>> {
@Override
public boolean test(final HashMap<String, Integer> m)
{
return m.get("a") > 10;
}
}
然后您可以在 JEXL 脚本中创建一个新实例:
var filterPredicate = new('my.custom.filter.predicate.MyCustomFilterPredicate');
Stream.map(Function)
也是如此:
public class MyCustomMapFunction implements Function<HashMap<String, Integer>, Integer> {
@Override
public Integer apply(final HashMap<String, Integer> m)
{
return m.get("b");
}
}
然后在您的脚本中再次创建一个新实例:
var mapFunction = new('my.custom.map.function.MyCustomMapFunction');
您的整个脚本将如下所示:
var x = {{'a':11,'b':5}, {'a':1,'b':15}, {'a':12,'b':25}, {'a':4,'b':35}, {'a':7,'b':45}};
var filterPredicate = new('my.custom.filter.predicate.MyCustomFilterPredicate');
var mapFunction = new('my.custom.map.function.MyCustomMapFunction');
return x.stream().filter(filterPredicate).map(mapFunction).toArray();
当然,您可能已经注意到谓词和函数实现的可重用性相当有限。这就是为什么我建议创建包装 JEXL 闭包的实现:
public class MyCustomFilterPredicate implements Predicate<Object> {
private final Closure closure;
public MyCustomFilterPredicate(final Closure closure) {
this.closure = closure;
}
@Override
public boolean test(final Object o)
{
return (boolean) closure.execute(JexlEngine.getThreadContext(), o);
}
}
public class MyCustomMapFunction implements Function<Object, Object> {
private final Closure closure;
public MyCustomMapFunction(final Closure closure) {
this.closure = closure;
}
@Override
public Object apply(final Object o)
{
return closure.execute(JexlEngine.getThreadContext(), o);
}
}
现在您可以按如下方式更改脚本并以各种方式重用这些 Java 类:
var x = {{'a':11,'b':5}, {'a':1,'b':15}, {'a':12,'b':25}, {'a':4,'b':35}, {'a':7,'b':45}};
var filterPredicate = new('my.custom.filter.predicate.MyCustomFilterPredicate', function(m){m['a']>10});
var mapFunction = new('my.custom.map.function.MyCustomMapFunction', function(m){m['b']});
return x.stream().filter(filterPredicate).map(mapFunction).toArray();