1概要

Spring Expression Language(SpEL)は、実行時にオブジェクトグラフのクエリと操作をサポートする強力な表現言語です。 XMLまたはアノテーションベースのSpring設定で使用できます。

この言語にはいくつかの演算子があります。

| =================================================== ======= |



|

演算子

|算術演算| 、 – 、** 、/、%、^、div、mod | Relational | <、>、==、!=、⇐、> =、lt、gt、eq、ne、le、ge | Logical | and、またはではない、


2演算子

これらの例では、アノテーションベースの設定を使います。 XML構成に関する詳細は、この記事の後半のセクションにあります。

SpEL式は



記号で始まり、中括弧で囲まれています。


#\ {expression}

プロパティは、

$

記号で始まり、中括弧で囲まれた同様の方法で参照できます。

$ \ {property.name}

プロパティプレースホルダにSpEL式を含めることはできませんが、式にプロパティ参照を含めることができます。

#{${someProperty} + 2}

上記の例では、

someProperty

の値が2であるとします。したがって、結果の式は2 2 2になり、4と評価されます。

** 2.1. 算術演算子

**

すべての基本算術演算子がサポートされています。

@Value("#{19 + 1}")//20
private double add;

@Value("#{'String1 ' + 'string2'}")//"String1 string2"
private String addString;

@Value("#{20 - 1}")//19
private double subtract;

@Value("#{10 **  2}")//20
private double multiply;

@Value("#{36/2}")//19
private double divide;

@Value("#{36 div 2}")//18, the same as for/operator
private double divideAlphabetic;

@Value("#{37 % 10}")//7
private double modulo;

@Value("#{37 mod 10}")//7, the same as for % operator
private double moduloAlphabetic;

@Value("#{2 ^ 9}")//512
private double powerOf;

@Value("#{(2 + 2) **  2 + 9}")//17
private double brackets;

除算およびモジュロ演算には、

/



div







mod

というアルファベットの別名があります。

+

演算子は文字列を連結するためにも使用できます。

** 2.2. 関係演算子および論理演算子

**

すべての基本的なリレーショナル操作と論理操作もサポートされています。

@Value("#{1 == 1}")//true
private boolean equal;

@Value("#{1 eq 1}")//true
private boolean equalAlphabetic;

@Value("#{1 != 1}")//false
private boolean notEqual;

@Value("#{1 ne 1}")//false
private boolean notEqualAlphabetic;

@Value("#{1 < 1}")//false
private boolean lessThan;

@Value("#{1 lt 1}")//false
private boolean lessThanAlphabetic;

@Value("#{1 <= 1}")//true
private boolean lessThanOrEqual;

@Value("#{1 le 1}")//true
private boolean lessThanOrEqualAlphabetic;

@Value("#{1 > 1}")//false
private boolean greaterThan;

@Value("#{1 gt 1}")//false
private boolean greaterThanAlphabetic;

@Value("#{1 >= 1}")//true
private boolean greaterThanOrEqual;

@Value("#{1 ge 1}")//true
private boolean greaterThanOrEqualAlphabetic;

すべての関係演算子にもアルファベットのエイリアスがあります。たとえば、XMLベースの設定では、山括弧を含む演算子(

<



⇐、


>



> =

)は使用できません。代わりに、

lt

(より小さい)、

le

(より小さいか等しい)、

gt

(より大きい)、または

ge

(より大きいか等しい)を使用できます。


2.3. 論理演算子

SpELはすべての基本的な論理演算をサポートします。

@Value("#{250 > 200 && 200 < 4000}")//true
private boolean and;

@Value("#{250 > 200 and 200 < 4000}")//true
private boolean andAlphabetic;

@Value("#{400 > 300 || 150 < 100}")//true
private boolean or;

@Value("#{400 > 300 or 150 < 100}")//true
private boolean orAlphabetic;

@Value("#{!true}")//false
private boolean not;

@Value("#{not true}")//false
private boolean notAlphabetic;

算術演算子および関係演算子と同様に、すべての論理演算子にもアルファベットのクローンがあります。

** 2.4. 条件付き演算子

**

条件演算子は、条件に応じて異なる値を挿入するために使用されます。

@Value("#{2 > 1 ? 'a' : 'b'}")//"a"
private String ternary;

三項演算子は、式の中でコンパクトなif-then-else条件付き論理を実行するために使用されます。この例では、

true

があるかどうかをチェックしようとしています。

三項演算子のもう1つの一般的な使用法は、変数が

null

であるかどうかを確認してから変数値またはデフォルトを返すことです。

@Value("#{someBean.someProperty != null ? someBean.someProperty : 'default'}")
private String ternary;

Elvis演算子は、Groovy言語で使用されている上記の場合の3項演算子構文を短縮する方法です。 SpELでも利用可能です。以下のコードは上記のコードと同等です。

@Value("#{someBean.someProperty ?: 'default'}")//Will inject provided string if someProperty is null
private String elvis;


2.5. SpELでの正規表現の使用


matches

演算子は、文字列が特定の正規表現に一致するかどうかを確認するために使用できます。

@Value("#{'100' matches '\\d+' }")//true
private boolean validNumericStringResult;

@Value("#{'100fghdjf' matches '\\d+' }")//false
private boolean invalidNumericStringResult;

@Value("#{'valid alphabetic string' matches '[a-zA-Z\\s]+' }")//true
private boolean validAlphabeticStringResult;

@Value("#{'invalid alphabetic string #$1' matches '[a-zA-Z\\s]+' }")//false
private boolean invalidAlphabeticStringResult;

@Value("#{someBean.someValue matches '\d+'}")//true if someValue contains only digits
private boolean validNumericValue;

** 2.6.

List

および

Map

オブジェクトへのアクセス+

**

SpELの助けを借りて、コンテキスト内の任意の

Map

または

List

の内容にアクセスできます。いくつかの労働者とその給与に関する情報を

List



Map

に格納する新しいBean

workersHolder

を作成します。

@Component("workersHolder")
public class WorkersHolder {
    private List<String> workers = new LinkedList<>();
    private Map<String, Integer> salaryByWorkers = new HashMap<>();

    public WorkersHolder() {
        workers.add("John");
        workers.add("Susie");
        workers.add("Alex");
        workers.add("George");

        salaryByWorkers.put("John", 35000);
        salaryByWorkers.put("Susie", 47000);
        salaryByWorkers.put("Alex", 12000);
        salaryByWorkers.put("George", 14000);
    }

   //Getters and setters
}

これでSpELを使ってコレクションの値にアクセスできます。

@Value("#{workersHolder.salaryByWorkers['John']}")//35000
private Integer johnSalary;

@Value("#{workersHolder.salaryByWorkers['George']}")//14000
private Integer georgeSalary;

@Value("#{workersHolder.salaryByWorkers['Susie']}")//47000
private Integer susieSalary;

@Value("#{workersHolder.workers[0]}")//John
private String firstWorker;

@Value("#{workersHolder.workers[3]}")//George
private String lastWorker;

@Value("#{workersHolder.workers.size()}")//4
private Integer numberOfWorkers;

** 3 Spring構成で使用する

**

** 3.1. Beanを参照する

**

この例では、XMLベースの設定でSpELを使用する方法を見ていきます。式は、BeanまたはBeanフィールド/メソッドを参照するために使用できます。たとえば、次のようなクラスがあるとします。

public class Engine {
    private int capacity;
    private int horsePower;
    private int numberOfCylinders;

  //Getters and setters
}

public class Car {
    private String make;
    private int model;
    private Engine engine;
    private int horsePower;

  //Getters and setters
}

それでは、式を使用して値を注入するアプリケーションコンテキストを作成します。

<bean id="engine" class="com.baeldung.spring.spel.Engine">
   <property name="capacity" value="3200"/>
   <property name="horsePower" value="250"/>
   <property name="numberOfCylinders" value="6"/>
</bean>
<bean id="someCar" class="com.baeldung.spring.spel.Car">
   <property name="make" value="Some make"/>
   <property name="model" value="Some model"/>
   <property name="engine" value="#{engine}"/>
   <property name="horsePower" value="#{engine.horsePower}"/>
</bean>


someCar

Beanを見てください。

someCar



engine

および

horsePower

フィールドは、それぞれ

engine

beanおよび

horsePower

フィールドへのBean参照である式を使用します。

アノテーションベースの設定で同じことをするには、

@ Value(“#\ {expression}”)

アノテーションを使います。

** 3.2. 構成での演算子の使用

**

この記事の最初のセクションの各演算子は、XMLおよび注釈ベースの構成で使用できます。ただし、XMLベースの設定では、山括弧演算子「<」は使用できません。代わりに、

lt

(小なり)や

le

(小なりまたは等しい)などのアルファベットのエイリアスを使用してください。注釈ベースの設定では、そのような制限はありません。

public class SpelOperators {
    private boolean equal;
    private boolean notEqual;
    private boolean greaterThanOrEqual;
    private boolean and;
    private boolean or;
    private String addString;

   //Getters and setters

    @Override
    public String toString() {
       //toString which include all fields
    }

今度は

spelOperators

Beanをアプリケーションコンテキストに追加します。

<bean id="spelOperators" class="com.baeldung.spring.spel.SpelOperators">
   <property name="equal" value="#{1 == 1}"/>
   <property name="notEqual" value="#{1 lt 1}"/>
   <property name="greaterThanOrEqual" value="#{someCar.engine.numberOfCylinders >= 6}"/>
   <property name="and" value="#{someCar.horsePower == 250 and someCar.engine.capacity lt 4000}"/>
   <property name="or" value="#{someCar.horsePower > 300 or someCar.engine.capacity > 3000}"/>
   <property name="addString" value="#{someCar.model + ' manufactured by ' + someCar.make}"/>
</bean>

コンテキストからそのBeanを取得したら、値が正しく注入されたことを確認できます。

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
SpelOperators spelOperators = (SpelOperators) context.getBean("spelOperators");

ここで、

spelOperators

beanの

toString

メソッドの出力を見ることができます。

----[equal=true, notEqual=false, greaterThanOrEqual=true, and=true,
or=true, addString=Some model manufactured by Some make]----

** 4プログラムによる式の解析

**

時には、設定という文脈の外側で式を解析したいかもしれません。幸い、これは

SpelExpressionParser

を使って可能です。前の例で見たすべての演算子を使用できますが、中括弧とハッシュ記号なしで使用する必要があります。つまり、Springの設定で使用するときに


演算子を使用して式を使用したい場合、構文は

#\ {1 1};

設定の外側で使用した場合は構文は単に

1 1

となります。

次の例では、前のセクションで定義した

Car

Beanと

Engine

Beanを使用します。

** 4.1.

ExpressionParser

を使う

**

簡単な例を見てみましょう。

ExpressionParser expressionParser = new SpelExpressionParser();
Expression expression = expressionParser.parseExpression("'Any string'");
String result = (String) expression.getValue();


ExpressionParser

は、式の文字列を解析します。この例では、SpELパーサーは単に文字列__Any Stringを式として評価します。当然のことながら、結果は「すべての文字列」になります。

SpELを設定に使用するのと同様に、メソッドの呼び出し、プロパティへのアクセス、またはコンストラクタの呼び出しに使用できます。

Expression expression = expressionParser.parseExpression("'Any string'.length()");
Integer result = (Integer) expression.getValue();

さらに、リテラルを直接操作する代わりに、コンストラクターを呼び出すこともできます。

Expression expression = expressionParser.parseExpression("new String('Any string').length()");


String

クラスの

bytes

プロパティにも同じ方法でアクセスできます。その結果、文字列はbyte[]表現になります。

Expression expression = expressionParser.parseExpression("'Any string'.bytes");
byte[]result = (byte[]) expression.getValue();

通常のJavaコードのように、メソッド呼び出しを連鎖させることができます。

Expression expression = expressionParser.parseExpression("'Any string'.replace(\" \", \"\").length()");
Integer result = (Integer) expression.getValue();

この場合、空白は空の文字列に置き換えられたため、結果は9になります。式の結果をキャストしたくない場合は、一般的なメソッド

T getValue(Class <T> desiredResultType)

を使用できます。このメソッドでは、返されるクラスの希望のタイプを指定できます。戻り値を

desiredResultType

にキャストできない場合、

EvaluationException

がスローされることに注意してください。

Integer result = expression.getValue(Integer.class);

最も一般的な使用方法は、特定のオブジェクトインスタンスに対して評価される式の文字列を提供することです。

Car car = new Car();
car.setMake("Good manufacturer");
car.setModel("Model 3");
car.setYearOfProduction(2014);

ExpressionParser expressionParser = new SpelExpressionParser();
Expression expression = expressionParser.parseExpression("model");

EvaluationContext context = new StandardEvaluationContext(car);
String result = (String) expression.getValue(context);

この場合、結果は

car

オブジェクトの

model

フィールドの値「

Model 3

」に等しくなります。

StandardEvaluationContext

クラスは、式が評価されるオブジェクトを指定します。

コンテキストオブジェクトの作成後に変更することはできません。


StandardEvaluationContext

は構築するのにコストがかかり、繰り返し使用すると、その後の式の評価をより迅速に実行できるようにキャッシュ状態を構築します。キャッシュのため、ルートオブジェクトが変更されない場合に可能であれば

StandardEvaluationContext

を再利用することをお勧めします。

ただし、ルートオブジェクトが繰り返し変更される場合は、次の例に示すメカニズムを使用できます。

Expression expression = expressionParser.parseExpression("model");
String result = (String) expression.getValue(car);

ここでは、SpEL式を適用するオブジェクトを表す引数を使用して

getValue

メソッドを呼び出します。以前と同様に、一般的な

getValue

メソッドを使用することもできます。

Expression expression = expressionParser.parseExpression("yearOfProduction > 2005");
boolean result = expression.getValue(car, Boolean.class);

** 4.2.

ExpressionParser

を使用して値を設定する

**

式を解析して返される

Expression

オブジェクトに対して

setValue

メソッドを使用すると、オブジェクトに値を設定できます。 SpELは型変換を行います。デフォルトでは、SpELは

org.springframework.core.convert.ConversionService

を使用します。型間で独自のカスタムコンバータを作成できます。

ConversionService

はジェネリックスに対応しているため、ジェネリックスと共に使用できます。実際に使用する方法を見てみましょう。

Car car = new Car();
car.setMake("Good manufacturer");
car.setModel("Model 3");
car.setYearOfProduction(2014);

CarPark carPark = new CarPark();
carPark.getCars().add(car);

StandardEvaluationContext context = new StandardEvaluationContext(carPark);

ExpressionParser expressionParser = new SpelExpressionParser();
expressionParser.parseExpression("cars[0].model").setValue(context, "Other model");

結果として生成された自動車オブジェクトは、「

モデル3

」から変更された

モデル



その他のモデル

」を持ちます。

** 4.3. パーサー構成

**

次の例では、次のクラスを使用します。

public class CarPark {
    private List<Car> cars = new ArrayList<>();

   //Getter and setter
}


SpelParserConfiguration

オブジェクトを使用してコンストラクタを呼び出すことで

ExpressionParser

を設定することができます。

EL1025E:(pos 4): The collection has '0' elements, index '0' is invalid

指定されたインデックスがnull(

autoGrowNullReferences、

コンストラクタへの最初のパラメータ)の場合は自動的に要素を作成できるようにパーサの動作を変更したり、初期サイズを超える要素に対応するように配列またはリストを自動的に拡張したりできます。

autoGrowCollections

、2番目のパラメータ)

SpelParserConfiguration config = new SpelParserConfiguration(true, true);
StandardEvaluationContext context = new StandardEvaluationContext(carPark);

ExpressionParser expressionParser = new SpelExpressionParser(config);
expressionParser.parseExpression("cars[0]").setValue(context, car);

Car result = carPark.getCars().get(0);

結果の

car

オブジェクトは、前の例の

carPark

オブジェクトの

cars

配列の最初の要素として設定された

car

オブジェクトと等しくなります。


5結論

SpELは、Springポートフォリオのすべての製品で使用できる強力でよくサポートされている式言語です。 Springアプリケーションを設定したり、あらゆるアプリケーションでより一般的なタスクを実行するためのパーサを書くために使用することができます。

この記事のコードサンプルはhttps://github.com/eugenp/tutorials/tree/master/spring-spel[リンクされたGitHubレポジトリ]にあります。