【问题标题】:Spring Expression Language (SpEL) for json access with list用于使用列表访问 json 的 Spring 表达式语言 (SpEL)
【发布时间】:2020-06-03 07:34:28
【问题描述】:

我试图理解为什么这不起作用?

  context.addPropertyAccessor(new JsonPropertyAccessor());

  Object j = mapper.readTree(
"{\"foo\": {\"bar\": [ { \"fizz\": 5, \"buzz\": 6, \"doo\": 9 }, {\"fizz\": 7}, {\"fizz\": 8} ] } })");

System.out.println(evaluate(j, "foo.bar.![doo == 9]"));

它总是打印:

[false, false, false]

我需要检查是否有任何 doo 包含 9。

【问题讨论】:

  • evaluate是什么方法?
  • foo.bar[?(@.doo==9)] 为您提供所有具有doo==9bars。如果您只需要真或假,那么foo.bar[?(@.doo)].doo==9
  • private static Object evaluate(Object target, String expression) { return parser.parseExpression(expression).getValue(context, target); }
  • 上面的表达式给了我一个异常。线程“main”中的异常 org.springframework.expression.spel.SpelParseException: Expression [foo.bar[?(@.doo==9)]] @ 10:EL1059E:@或&后面只能跟标识符或带引号的名称

标签: spring spring-el


【解决方案1】:

如果您不需要使用 SPEL,您可以使用 Jayway JsonPath 轻松完成

包含依赖:

<dependency>
    <groupId>com.jayway.jsonpath</groupId>
    <artifactId>json-path</artifactId>
    <version>2.4.0</version>
</dependency>

然后使用JsonPath 并查询:

Srgin json = "{\"foo\": {\"bar\": [ { \"fizz\": 5, \"buzz\": 6, \"doo\": 9 },
    {\"fizz\": 7}, {\"fizz\": 8, \"doo\": 6} ] } })";

JSONArray array = JsonPath.read(json, "foo.bar[?(@.doo==9)]");

// now array is a List of size 1, since second "doo" is not equal 9
// using array.get(0) you can get first object as a HashMap<String, Object>

通过上述链接,您可以找到有关 JsonPath 查询的更多详细信息。


如果您仍需要将 JsonPath 与 SPEL 集成,您可以将解析功能添加到评估上下文中。幸运的是,您已经使用了带有 JsonPathUtils 类和 evaluate(String, String) 方法的 spring-integration。

StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
Method method = BeanUtils.resolveSignature("evaluate", JsonPathUtils.class);
evaluationContext.registerFunction("jsonPath", method);

String json = "{\"foo\": {\"bar\": [ { \"fizz\": 5, \"buzz\": 6, \"doo\": 9 }, " +
            "{\"fizz\": 7}, {\"fizz\": 8, \"doo\": 7} ] } })";
evaluationContext.setVariable("foo", json);    

ExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("#jsonPath(#foo, 'foo.bar[?(@.doo>6)]')");
Object result = expression.getValue(evaluationContext);
//now result contains still the same JSONArray

最后我找到了你的问题的原因。首先:猜猜是什么返回表达式foo.bar.doo?它不是字符串或整数值。它返回一个ToStringFriendlyJsonNode 的实例。所以doo==9 将永远给你false,因为它们不能相等。此外,您不能使用&gt;&lt;,因为不允许比较ObjectInteger。因此,您需要在比较之前转换为合适的类型。

 expression.getValue("foo.bar.![doo!=null and new Integer(doo.toString()) == 9]");

我们还需要检查doo 是否存在,这就是我们需要检查null 的原因。 ToStringFriendlyJsonNode 只能提供字符串值。这就是我们必须使用ToString() 的原因。如您所见,原生 SPEL 不方便且过于冗长,因为它不应该用于复杂的 Json 查询。

【讨论】:

  • 我想使用 JsonPath 对我来说是一个不太可行的选择,因为我想在表达式中使用一些内置的 java 方法和 spring bean 中的一些函数。因此,SpEL 更容易,而不必注册很多自定义函数。仍然想知道为什么我的原始表达式在 SpEL + JsonPropertyAccessor 中不起作用。
  • @user1189332 我从未使用过 Jackson API(在 JsonPropertyAccessor 下)进行查询。我什至根本不知道它可以处理查询。但为了以防万一,我更新了我的答案并展示了如何将 JsonPath 与 SPEL 集成。希望它会以某种方式有用。
  • @user1189332 我更新了答案。抱歉,在找到解决方案之前不能停止)
猜你喜欢
  • 2014-01-14
  • 2016-06-27
  • 2023-03-28
  • 2011-10-04
  • 1970-01-01
  • 1970-01-01
  • 2012-03-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多