Properties, Arrays, Lists, Maps, and Indexers
Spring 表达式语言支持在对象图中导航并索引到各种结构中。
The Spring Expression Language provides support for navigating object graphs and indexing into various structures.
数值索引值从零开始,例如在 Java 中访问数组中的第 nth 个元素时。 |
Numerical index values are zero-based, such as when accessing the nth element of an array in Java. |
有关如何使用空安全运算符浏览对象图,并对各种结构进行索引的详细信息,请参阅 Safe Navigation Operator 部分。 |
See the Safe Navigation Operator section for details on how to navigate object graphs and index into various structures using the null-safe operator. |
Property Navigation
您可以通过使用句点指示嵌套属性值来导航对象图中的属性引用。Inventor
类、pupin
和 tesla
的实例已使用已在 Classes used in the examples 部分中列出的数据填充。通过导航 down 对象图并获取特斯拉的出生年份和普平的出生城市,我们使用以下表达式:
You can navigate property references within an object graph by using a period to indicate
a nested property value. The instances of the Inventor
class, pupin
and tesla
, were
populated with data listed in the
Classes used in the examples section. To
navigate down the object graph and get Tesla’s year of birth and Pupin’s city of birth,
we use the following expressions:
-
Java
-
Kotlin
// evaluates to 1856
int year = (Integer) parser.parseExpression("birthdate.year + 1900").getValue(context);
// evaluates to "Smiljan"
String city = (String) parser.parseExpression("placeOfBirth.city").getValue(context);
// evaluates to 1856
val year = parser.parseExpression("birthdate.year + 1900").getValue(context) as Int
// evaluates to "Smiljan"
val city = parser.parseExpression("placeOfBirth.city").getValue(context) as String
属性名称的首字母可以不区分大小写。 因此,上面的示例中的表达式可以分别写成 Case insensitivity is allowed for the first letter of property names. Thus, the
expressions in the above example may be written as |
Indexing into Arrays and Collections
数组或集合(例如,Set 或 List)的第 n 个元素可以通过使用方括号表示法获取,如下面的示例所示。
The nth element of an array or collection (for example, a Set
or List
) can be
obtained by using square bracket notation, as the following example shows.
如果索引集合是 java.util.List,则可以通过 list.get(n) 直接访问第 n 个元素。 If the indexed collection is a 对于任何其他类型的 Collection,将通过使用其 Iterator 遍历集合并返回遇到的第 n 个元素来访问第 n 个元素。 For any other type of |
-
Java
-
Kotlin
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
// Inventions Array
// evaluates to "Induction motor"
String invention = parser.parseExpression("inventions[3]").getValue(
context, tesla, String.class);
// Members List
// evaluates to "Nikola Tesla"
String name = parser.parseExpression("members[0].name").getValue(
context, ieee, String.class);
// List and Array Indexing
// evaluates to "Wireless communication"
String invention = parser.parseExpression("members[0].inventions[6]").getValue(
context, ieee, String.class);
val parser = SpelExpressionParser()
val context = SimpleEvaluationContext.forReadOnlyDataBinding().build()
// Inventions Array
// evaluates to "Induction motor"
val invention = parser.parseExpression("inventions[3]").getValue(
context, tesla, String::class.java)
// Members List
// evaluates to "Nikola Tesla"
val name = parser.parseExpression("members[0].name").getValue(
context, ieee, String::class.java)
// List and Array Indexing
// evaluates to "Wireless communication"
val invention = parser.parseExpression("members[0].inventions[6]").getValue(
context, ieee, String::class.java)
Indexing into Strings
字符串的第 n 个字符可以通过在方括号中指定索引来获取,如下面的示例所示。
The nth character of a string can be obtained by specifying the index within square brackets, as demonstrated in the following example.
字符串的 nth 字符将计算为 |
The nth character of a string will evaluate to a |
-
Java
-
Kotlin
// evaluates to "T" (8th letter of "Nikola Tesla")
String character = parser.parseExpression("members[0].name[7]")
.getValue(societyContext, String.class);
// evaluates to "T" (8th letter of "Nikola Tesla")
val character = parser.parseExpression("members[0].name[7]")
.getValue(societyContext, String::class.java)
Indexing into Maps
映射的内容是通过在方括号中指定键值来获取的。 在以下示例中,由于 officers 映射的键是字符串,因此我们可以指定诸如 “president'” 的字符串字面量:
The contents of maps are obtained by specifying the key value within square brackets. In
the following example, because keys for the officers
map are strings, we can specify
string literals such as ’president'`:
-
Java
-
Kotlin
// Officer's Map
// evaluates to Inventor("Pupin")
Inventor pupin = parser.parseExpression("officers['president']")
.getValue(societyContext, Inventor.class);
// evaluates to "Idvor"
String city = parser.parseExpression("officers['president'].placeOfBirth.city")
.getValue(societyContext, String.class);
String countryExpression = "officers['advisors'][0].placeOfBirth.country";
// setting values
parser.parseExpression(countryExpression)
.setValue(societyContext, "Croatia");
// evaluates to "Croatia"
String country = parser.parseExpression(countryExpression)
.getValue(societyContext, String.class);
// Officer's Map
// evaluates to Inventor("Pupin")
val pupin = parser.parseExpression("officers['president']")
.getValue(societyContext, Inventor::class.java)
// evaluates to "Idvor"
val city = parser.parseExpression("officers['president'].placeOfBirth.city")
.getValue(societyContext, String::class.java)
val countryExpression = "officers['advisors'][0].placeOfBirth.country"
// setting values
parser.parseExpression(countryExpression)
.setValue(societyContext, "Croatia")
// evaluates to "Croatia"
val country = parser.parseExpression(countryExpression)
.getValue(societyContext, String::class.java)
Indexing into Objects
可以通过在方括号中指定属性的名称来获取对象的属性。 这类似于基于其键访问映射的值。 以下示例演示了如何索引到对象以检索特定属性。
A property of an object can be obtained by specifying the name of the property within square brackets. This is analogous to accessing the value of a map based on its key. The following example demonstrates how to index into an object to retrieve a specific property.
-
Java
-
Kotlin
// Create an inventor to use as the root context object.
Inventor tesla = new Inventor("Nikola Tesla");
// evaluates to "Nikola Tesla"
String name = parser.parseExpression("#root['name']")
.getValue(context, tesla, String.class);
// Create an inventor to use as the root context object.
val tesla = Inventor("Nikola Tesla")
// evaluates to "Nikola Tesla"
val name = parser.parseExpression("#root['name']")
.getValue(context, tesla, String::class.java)
Indexing into Custom Structures
从 Spring Framework 6.2 开始,Spring 表达式语言支持通过允许开发者实现并注册带有 IndexAccessor
的 EvaluationContext
的自定义结构进行索引。如果你想要支持依赖自定义索引访问器的 compilation 表达式,该索引访问器必须实现 CompilableIndexAccessor
SPI。
Since Spring Framework 6.2, the Spring Expression Language supports indexing into custom
structures by allowing developers to implement and register an IndexAccessor
with the
EvaluationContext
. If you would like to support
compilation of
expressions that rely on a custom index accessor, that index accessor must implement the
CompilableIndexAccessor
SPI.
为了支持常见用例,Spring 提供了一个内置的 ReflectiveIndexAccessor,它是一个灵活的 IndexAccessor,它使用反射从目标对象的索引结构中读取并选择性地写入。 索引结构可以通过 public 读方法(在读取时)或 public 写方法(在写入时)进行访问。 读方法和写方法之间的关系基于一个惯例,该惯例适用于索引结构的典型实现。
To support common use cases, Spring provides a built-in ReflectiveIndexAccessor
which
is a flexible IndexAccessor
that uses reflection to read from and optionally write to
an indexed structure of a target object. The indexed structure can be accessed through a
public
read-method (when being read) or a public
write-method (when being written).
The relationship between the read-method and write-method is based on a convention that
is applicable for typical implementations of indexed structures.
|
|
以下代码清单定义了一个 Color 枚举和一个 FruitMap 类型,它的行为类似于映射但并不实现 java.util.Map 接口。 因此,如果要在 SpEL 表达式中的 FruitMap 中进行索引,则需要注册一个 IndexAccessor。
The following code listings define a Color
enum and FruitMap
type that behaves like a
map but does not implement the java.util.Map
interface. Thus, if you want to index into
a FruitMap
within a SpEL expression, you will need to register an IndexAccessor
.
public enum Color {
RED, ORANGE, YELLOW
}
public class FruitMap {
private final Map<Color, String> map = new HashMap<>();
public FruitMap() {
this.map.put(Color.RED, "cherry");
this.map.put(Color.ORANGE, "orange");
this.map.put(Color.YELLOW, "banana");
}
public String getFruit(Color color) {
return this.map.get(color);
}
public void setFruit(Color color, String fruit) {
this.map.put(color, fruit);
}
}
可以 new
ReflectiveIndexAccessor(FruitMap.class, Color.class, "getFruit")
创建 FruitMap
的只读 IndexAccessor
。通过注册该访问器并注册 FruitMap
作为名为 #fruitMap
的变量,SpEL 表达式 #fruitMap[T(example.Color).RED]
将评估为 "cherry"
。
A read-only IndexAccessor
for FruitMap
can be created via new
ReflectiveIndexAccessor(FruitMap.class, Color.class, "getFruit")
. With that accessor
registered and a FruitMap
registered as a variable named #fruitMap
, the SpEL
expression #fruitMap[T(example.Color).RED]
will evaluate to "cherry"
.
可以 new
ReflectiveIndexAccessor(FruitMap.class, Color.class, "getFruit", "setFruit")
创建 FruitMap
的可读写 IndexAccessor
。通过注册该访问器并注册 FruitMap
作为名为 #fruitMap
的变量,SpEL 表达式 #fruitMap[T(example.Color).RED] = 'strawberry'
可用于将红色颜色的水果映射从 "cherry"
更改为 "strawberry"
。
A read-write IndexAccessor
for FruitMap
can be created via new
ReflectiveIndexAccessor(FruitMap.class, Color.class, "getFruit", "setFruit")
. With that
accessor registered and a FruitMap
registered as a variable named #fruitMap
, the SpEL
expression #fruitMap[T(example.Color).RED] = 'strawberry'
can be used to change the
fruit mapping for the color red from "cherry"
to "strawberry"
.
以下示例演示了如何注册一个 ReflectiveIndexAccessor
以在 FruitMap
中建立索引,然后在 SpEL 表达式中对 FruitMap
建立索引。
The following example demonstrates how to register a ReflectiveIndexAccessor
to index
into a FruitMap
and then index into the FruitMap
within a SpEL expression.
-
Java
-
Kotlin
// Create a ReflectiveIndexAccessor for FruitMap
IndexAccessor fruitMapAccessor = new ReflectiveIndexAccessor(
FruitMap.class, Color.class, "getFruit", "setFruit");
// Register the IndexAccessor for FruitMap
context.addIndexAccessor(fruitMapAccessor);
// Register the fruitMap variable
context.setVariable("fruitMap", new FruitMap());
// evaluates to "cherry"
String fruit = parser.parseExpression("#fruitMap[T(example.Color).RED]")
.getValue(context, String.class);
// Create a ReflectiveIndexAccessor for FruitMap
val fruitMapAccessor = ReflectiveIndexAccessor(
FruitMap::class.java, Color::class.java, "getFruit", "setFruit")
// Register the IndexAccessor for FruitMap
context.addIndexAccessor(fruitMapAccessor)
// Register the fruitMap variable
context.setVariable("fruitMap", FruitMap())
// evaluates to "cherry"
val fruit = parser.parseExpression("#fruitMap[T(example.Color).RED]")
.getValue(context, String::class.java)