このバージョンはまだ開発中であり、まだ安定しているとは見なされていません。最新の安定バージョンについては、Spring Framework 6.2.2 を使用してください! |
関数
#functionName(…)
構文を使用して式内で呼び出すことができるユーザー定義関数を登録することで SpEL を継承できます。また、標準メソッド呼び出しと同様に、関数呼び出しでは varargs もサポートされています。
関数は、setVariable()
メソッドを介して EvaluationContext
実装の変数として登録できます。
|
関数は評価コンテキストの変数と共通の名前空間を共有するため、関数名と変数名が重複しないように注意する必要があります。 |
次の例は、java.lang.reflect.Method
を使用してリフレクション経由で呼び出されるユーザー定義関数を登録する方法を示しています。
Java
Kotlin
Method method = ...;
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
context.setVariable("myFunction", method);
val method: Method = ...
val context = SimpleEvaluationContext.forReadOnlyDataBinding().build()
context.setVariable("myFunction", method)
例: 文字列を逆にする次のユーティリティメソッドを検討します。
Java
Kotlin
public abstract class StringUtils {
public static String reverseString(String input) {
return new StringBuilder(input).reverse().toString();
}
}
fun reverseString(input: String): String {
return StringBuilder(input).reverse().toString()
}
次の例に示すように、前述の方法を登録して使用できます。
Java
Kotlin
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
context.setVariable("reverseString",
StringUtils.class.getMethod("reverseString", String.class));
// evaluates to "olleh"
String helloWorldReversed = parser.parseExpression(
"#reverseString('hello')").getValue(context, String.class);
val parser = SpelExpressionParser()
val context = SimpleEvaluationContext.forReadOnlyDataBinding().build()
context.setVariable("reverseString", ::reverseString.javaMethod)
// evaluates to "olleh"
val helloWorldReversed = parser.parseExpression(
"#reverseString('hello')").getValue(context, String::class.java)
関数は java.lang.invoke.MethodHandle
として登録することもできます。これにより、登録前に MethodHandle
ターゲットとパラメーターが完全にバインドされている場合、より効率的な使用例が可能になる可能性があります。ただし、部分的にバインドされたハンドルもサポートされます。
テンプレートと可変数の引数 ( varargs ) に従ってメッセージを生成する String#formatted(Object…)
インスタンスメソッドを考えてみましょう。
次の例に示すように、formatted
メソッドを MethodHandle
として登録して使用できます。
Java
Kotlin
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
MethodHandle mh = MethodHandles.lookup().findVirtual(String.class, "formatted",
MethodType.methodType(String.class, Object[].class));
context.setVariable("message", mh);
// evaluates to "Simple message: <Hello World>"
String message = parser.parseExpression("#message('Simple message: <%s>', 'Hello World', 'ignored')")
.getValue(context, String.class);
val parser = SpelExpressionParser()
val context = SimpleEvaluationContext.forReadOnlyDataBinding().build()
val mh = MethodHandles.lookup().findVirtual(String::class.java, "formatted",
MethodType.methodType(String::class.java, Array<Any>::class.java))
context.setVariable("message", mh)
// evaluates to "Simple message: <Hello World>"
val message = parser.parseExpression("#message('Simple message: <%s>', 'Hello World', 'ignored')")
.getValue(context, String::class.java)
前述のように、MethodHandle
をバインドし、バインドされた MethodHandle
を登録することもサポートされています。ターゲットとすべての引数の両方がバインドされている場合、パフォーマンスが向上する可能性があります。その場合、次の例に示すように、SpEL 式に引数は必要ありません。
Java
Kotlin
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
String template = "This is a %s message with %s words: <%s>";
Object varargs = new Object[] { "prerecorded", 3, "Oh Hello World!", "ignored" };
MethodHandle mh = MethodHandles.lookup().findVirtual(String.class, "formatted",
MethodType.methodType(String.class, Object[].class))
.bindTo(template)
// Here we have to provide the arguments in a single array binding:
.bindTo(varargs);
context.setVariable("message", mh);
// evaluates to "This is a prerecorded message with 3 words: <Oh Hello World!>"
String message = parser.parseExpression("#message()")
.getValue(context, String.class);
val parser = SpelExpressionParser()
val context = SimpleEvaluationContext.forReadOnlyDataBinding().build()
val template = "This is a %s message with %s words: <%s>"
val varargs = arrayOf("prerecorded", 3, "Oh Hello World!", "ignored")
val mh = MethodHandles.lookup().findVirtual(String::class.java, "formatted",
MethodType.methodType(String::class.java, Array<Any>::class.java))
.bindTo(template)
// Here we have to provide the arguments in a single array binding:
.bindTo(varargs)
context.setVariable("message", mh)
// evaluates to "This is a prerecorded message with 3 words: <Oh Hello World!>"
val message = parser.parseExpression("#message()")
.getValue(context, String::class.java)