当前位置: 首页 > 知识库问答 >
问题:

如何使用SpEL通过评估在根对象中的字段中维护的其他子对象列表来选择和返回集合中的根对象

佟阳飙
2023-03-14

我正在使用的服务是在Java8中运行的。我正在使用SpEL根据输入表达式过滤对象的通用集合。当表达式计算RootObject中的顶级基本字段时,我正在成功筛选集合。SpEL集合选择功能根据RootObject中键、标签和/或类型的表达式返回经过筛选的RootObject集合。这个案子运作良好。

ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext();
context.setVariable("collection", collection);
String selectionExpression = "#collection.?[key matches 'foo|foo2|foo3']";

我的问题是如何过滤原始集合返回RootObject的基于RootObject中的值列表中的其他对象中的计算字段的集合?即,返回所有在RootObject.values中具有列表项的RootObject,其中bject.name==foo或其他bject.count

集合对象的外观如下所示:

public class RootObject {

    String key;
    String label;
    String type;
    List<OtherObject> values;

    public RootObject() {}

    public RootObject(String key, String label, String type, List<OtherObject> values) {
        this.key = key;
        this.label = label;
        this.type = type;
        this.values = values;
    }
    public String getKey() {
        return key;
    }
    public void setKey(String key) {
        this.key = key;
    }
    public String getLabel() {
        return label;
    }
    public void setLabel(String label) {
        this.label = label;
    }
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    } 
    public List<OtherObject> getValues() {
        return values;
    }
    public void setValues(List<OtherObject> values) {
        this.values = values;
    }
}


public class OtherObject {
    private String name;
    private String label;
    private Integer count;
    private Integer totalCount;
    private Boolean isSelected;

    public OtherObject() {}

    public OtherObject(String name, String label, int count, int totalCount, boolean isSelected) {
        this.name = name;
        this.label = label;
        this.setCount(count);
        this.isSelected = isSelected;
        this.totalCount = totalCount;
    }

    public String getName() {
        return this.name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getLabel() {
        return this.label;
    }
    public void setLabel(String label) {
        this.label = label;
    }
    public Integer getCount() {
        return this.count;
    }
    public void setCount(Integer count) {
        this.count = count;
    }
    public Integer getTotalCount() {
        return this.totalCount;
    }
    public void setTotalCount(Integer totalCount) {
        this.totalCount = totalCount;
    }
    public Boolean getIsSelected() {
        return this.isSelected;
    }
    public void setIsSelected(Boolean isSelected) {
    this.isSelected = isSelected;
    }
}

共有2个答案

路欣荣
2023-03-14

你只需要做两个投影。在根对象集合中,您希望投影以查找那些根对象,其中在其值集合中,所需条件的投影不是空的。

#collection.?[!(values.?[name == 'foo' or count > 10 or isSelected == true].isEmpty())]

投影只是生成另一个列表,您可以基于任何布尔表达式进行投影。在一个投影中,您可以继续使用SpEL来计算布尔表达式,包括另一个投影。您只需要记住,投影返回一个列表,而投影条件需要是一个布尔值,因此您需要实际检查您正在查找的条件(在本例中,列表不是空的)。

下面是我做的测试,以向自己证明事实上它是正确的语法,并且工作正常:

@Test
public void test() {
    final OtherObject otherFooOneNotSelected = new OtherObject("foo", "", 1, 1, false);
    final OtherObject otherBarOneNotSelected = new OtherObject("bar", "", 1, 1, false);
    final OtherObject otherFooTwelveNotSelected = new OtherObject("foo", "", 12, 12, false);
    final OtherObject otherBarTwelveNotSelected = new OtherObject("bar", "", 12, 12, false);
    final OtherObject otherFooOneSelected = new OtherObject("foo", "", 1, 1, true);
    final OtherObject otherBarOneSelected = new OtherObject("bar", "", 1, 1, true);
    final OtherObject otherFooTwelveSelected = new OtherObject("foo", "", 12, 12, true);
    final OtherObject otherBarTwelveSelected = new OtherObject("bar", "", 12, 12, true);
    final RootObject rootNoValues = new RootObject("noValues", "", "", Collections.<OtherObject>emptyList());
    final RootObject rootFooOneNotSelected = new RootObject("rootFooOneNotSelected", "", "", Collections.singletonList(otherFooOneNotSelected));
    final RootObject rootBarOneNotSelected = new RootObject("rootBarOneNotSelected", "", "", Collections.singletonList(otherBarOneNotSelected));
    final RootObject rootBarTwelveNotSelected = new RootObject("rootBarTwelveNotSelected", "", "", Collections.singletonList(otherBarTwelveNotSelected));
    final RootObject rootAllValues = new RootObject("allValues", "", "", Arrays.asList(
            otherFooOneNotSelected,
            otherBarOneNotSelected,
            otherFooTwelveNotSelected,
            otherBarTwelveNotSelected,
            otherFooOneSelected,
            otherBarOneSelected,
            otherFooTwelveSelected,
            otherBarTwelveSelected));
    final Collection<RootObject> collection = Arrays.asList(rootNoValues, rootFooOneNotSelected, rootBarOneNotSelected, rootBarTwelveNotSelected, rootAllValues);

    final ExpressionParser parser = new SpelExpressionParser();
    final StandardEvaluationContext context = new StandardEvaluationContext();
    context.setVariable("collection", collection);
    final String selectionExpression = "#collection.?[!(values.?[name == 'foo' or count > 10 or isSelected == true].isEmpty())]";
    final List<?> result = (List<?>) parser.parseExpression(selectionExpression).getValue(context);
    assertEquals("Result", Arrays.asList(rootFooOneNotSelected, rootBarTwelveNotSelected, rootAllValues), result);
}
商和颂
2023-03-14

我不认为你能用纯粹的语言做到这一点;您可以在Java中实现它并注册一个自定义SpEL函数。

 类似资料: