屬性、陣列、列表、對映和索引器
Spring Expression Language 提供導航物件圖和索引各種結構的支援。
| 數值索引值是基於零的,例如在 Java 中訪問陣列的第 n 個元素時。 |
| 有關如何使用 null 安全運算子導航物件圖和索引到各種結構的詳細資訊,請參閱安全導航運算子部分。 |
屬性導航
您可以透過使用句點指示巢狀屬性值來導航物件圖中的屬性引用。Inventor 類的例項 pupin 和 tesla 已填充了示例中使用的類部分中列出的資料。為了向下導航物件圖並獲取 Tesla 的出生年份和 Pupin 的出生城市,我們使用以下表達式
-
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
|
屬性名稱的第一個字母允許不區分大小寫。因此,上述示例中的表示式可以分別寫為 |
陣列和集合的索引
陣列或集合(例如,Set 或 List)的第 n 個元素可以透過使用方括號表示法獲得,如下例所示。
|
如果索引集合是 對於任何其他型別的 |
-
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)
字串索引
字串的第 n 個字元可以透過在方括號中指定索引來獲得,如下例所示。
字串的第 n 個字元將評估為 java.lang.String,而不是 java.lang.Character。 |
-
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)
對映索引
透過在方括號中指定鍵值來獲取對映的內容。在以下示例中,由於 officers 對映的鍵是字串,我們可以指定字串字面量,例如 '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)
物件索引
可以透過在方括號中指定屬性名稱來獲取物件的屬性。這類似於基於其鍵訪問對映的值。以下示例演示瞭如何索引物件以檢索特定屬性。
-
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)
自定義結構索引
自 Spring Framework 6.2 起,Spring Expression Language 透過允許開發人員實現 IndexAccessor 並將其註冊到 EvaluationContext 來支援自定義結構的索引。如果您希望支援依賴自定義索引訪問器的表示式的編譯,則該索引訪問器必須實現 CompilableIndexAccessor SPI。
為了支援常見用例,Spring 提供了一個內建的 ReflectiveIndexAccessor,它是一個靈活的 IndexAccessor,它使用反射從目標物件的索引結構中讀取並可選地寫入。索引結構可以透過 public 讀取方法(讀取時)或 public 寫入方法(寫入時)訪問。讀取方法和寫入方法之間的關係基於適用於索引結構典型實現的約定。
ReflectiveIndexAccessor 還實現了 CompilableIndexAccessor,以便支援讀取訪問的位元組碼編譯。但請注意,配置的讀取方法必須透過 public 類或 public 介面可呼叫,編譯才能成功。 |
以下程式碼清單定義了一個 Color 列舉和 FruitMap 型別,它表現得像一個對映,但沒有實現 java.util.Map 介面。因此,如果您想在 SpEL 表示式中索引 FruitMap,您將需要註冊一個 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"。
可以通 new ReflectiveIndexAccessor(FruitMap.class, Color.class, "getFruit", "setFruit") 建立 FruitMap 的讀寫 IndexAccessor。註冊該訪問器並將 FruitMap 註冊為名為 #fruitMap 的變數後,SpEL 表示式 #fruitMap[T(example.Color).RED] = 'strawberry' 可用於將紅色水果的對映從 "cherry" 更改為 "strawberry"。
以下示例演示瞭如何註冊 ReflectiveIndexAccessor 以索引 FruitMap,然後在 SpEL 表示式中索引 FruitMap。
-
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)