首页 > 学院 > 开发设计 > 正文

【Spring】Spring Framework Reference Documentation中文版9

2019-11-11 05:10:13
字体:
来源:转载
供稿:网友

10. SPRing Expression Language (SpEL)

spring的表达式语言

 

10.1 Introduction

介绍

 

The Spring Expression Language (SpEL for short) is a powerful expression language that supports querying and manipulating an object graph at runtime. The language syntax is similar to Unified EL but offers additional features, most notably method invocation and basic string templating functionality.

spring表达式语言(使用SpEL来简化)是一个强大的表达式语言用于支持查询和管理object在运行时。语言的语法和统一的EL类似但是提供了其他的特性,大部分方法的调用和基本的字符串模板功能。

 

While there are several other java expression languages available, OGNL, MVEL, and JBoss EL, to name a few, the Spring Expression Language was created to provide the Spring community with a single well supported expression language that can be used across all the products in the Spring portfolio. Its language features are driven by the requirements of the projects in the Spring portfolio, including tooling requirements for code completion support within the eclipse based Spring Tool Suite. That said, SpEL is based on a technology agnostic API allowing other expression language implementations to be integrated should the need arise.

目前有一个其他的java表达式语言,如OGNL、MVEL和JBoss EL,为了区别,spring表达式语言是spring社区使用的一个简单的支持表达式语言可以用于跨spring的产品。语言特性通过需要定义在spring的程序中,包括代码完成支持的工具如基于eclipse的spring工具箱。SpEL是一个基于技术不可知的API允许其他的表达式语言实现用于集成需要的。

 

While SpEL serves as the foundation for expression evaluation within the Spring portfolio, it is not directly tied to Spring and can be used independently. In order to be self contained, many of the examples in this chapter use SpEL as if it were an independent expression language. This requires creating a few bootstrapping infrastructure classes such as the parser. Most Spring users will not need to deal with this infrastructure and will instead only author expression strings for evaluation. An example of this typical use is the integration of SpEL into creating xml or annotated based bean definitions as shown in the section Expression support for defining bean definitions.

SpEL服务作为一个基础用于表达式在spring中,并没有直接和spring相关联可以独立使用。为了自包含,在这节中许多的例子使用SpEL由于它是一个独立的表达式语言。允许创建一些基础设置类例如解析器。大部分spring的用户将不需要处理基础架构只是用于评估的表达式字符串。一个典型的案例使用就是在创建XML中集成SpEL或注解bean的定义就像在“表达式支持用于bean的定义”中描述的一样。

 

This chapter covers the features of the expression language, its API, and its language syntax. In several places an Inventor and Inventor’s Society class are used as the target objects for expression evaluation. These class declarations and the data used to populate them are listed at the end of the chapter.

这一节包含了表达式语言的特性、API和语法。在一些地方Inventor和Inventor的Society类用在目标object用于表达式评估。这些类定义和数据通常组成他们并列在章节的末尾。

 

10.2 Feature Overview

特性概览

 

The expression language supports the following functionality

表达式语言支持如下的功能

 

    Literal expressions

文字化表达

    Boolean and relational Operators

布尔和关系操作符

    Regular expressions

正则表达式

    Class expressions

类表达式

    accessing properties, arrays, lists, maps

访问属性、数组、list和map

    Method invocation

方法调用

    Relational operators

关系操作符

    Assignment

声明

    Calling constructors

调用构造器

    Bean references

bean的引用

    Array construction

数组的构造

    Inline lists

内嵌的list

    Inline maps

内嵌的map

    Ternary operator

三目表达式

    Variables

变量

    User defined functions

用户自定义函数

    Collection projection

集合映射

    Collection selection

集合选择

    Templated expressions

模板表达式

 

10.3 Expression Evaluation using Spring’s Expression Interface

使用spring的表达式接口来评估表达式

 

This section introduces the simple use of SpEL interfaces and its expression language. The complete language reference can be found in the section Language Reference.

这节介绍简要使用SpEL接口和他的表达式语言。详细的语言参考可以在“语言参考”这一节中找到。

 

The following code introduces the SpEL API to evaluate the literal string expression 'Hello World'.

下面的代码使用了SpEL的API用于评价字符串表达式“Hello World”

 

ExpressionParser parser = new SpelExpressionParser();

Expression exp = parser.parseExpression("'Hello World'");

String message = (String) exp.getValue();

 

The value of the message variable is simply 'Hello World'.

消息变量的值是"Hello World"

 

The SpEL classes and interfaces you are most likely to use are located in the packages org.springframework.expression and its sub packages and spel.support.

你最常用的SpEL类和接口在org.springframework.expression包中,包括他的子包spel.support。

 

The interface ExpressionParser is responsible for parsing an expression string. In this example the expression string is a string literal denoted by the surrounding single quotes. The interface Expression is responsible for evaluating the previously defined expression string. There are two exceptions that can be thrown, ParseException and EvaluationException when calling parser.parseExpression and exp.getValue respectively.

ExpressionParser接口用于解析表达式字符串。在这个例子中表达式字符串是一个通过单引号包围的文本形式字符串。Expression接口用于解析之前定义的表达式字符串。有两个异常可能会被抛出,ParseException和EvaluationException当分别调用parser.parseExpression和exp.getValue。

 

SpEL supports a wide range of features, such as calling methods, accessing properties, and calling constructors.

SpEL支持许多特性,例如调用方法、访问属性和访问构造器。

 

As an example of method invocation, we call the concat method on the string literal.

作为方法调用的例子,我们可以在字符串上调用concat方法。

 

ExpressionParser parser = new SpelExpressionParser();

Expression exp = parser.parseExpression("'Hello World'.concat('!')");

String message = (String) exp.getValue();

 

The value of message is now 'Hello World!'.

消息的值现在是"Hello World"

 

As an example of calling a JavaBean property, the String property Bytes can be called as shown below.

作为一个调用JavaBean属性的例子,字符串属性可以如下的方式被使用。

 

ExpressionParser parser = new SpelExpressionParser();

 

// invokes 'getBytes()'

// 调用getBytes()

Expression exp = parser.parseExpression("'Hello World'.bytes");

byte[] bytes = (byte[]) exp.getValue();

 

SpEL also supports nested properties using standard dot notation, i.e. prop1.prop2.prop3 and the setting of property values

SpEL也支持内置的属性通过使用点符号,例如,prop1.prop2.prop3和属性的设置

 

Public fields may also be accessed.

公用的域也可以被访问

 

ExpressionParser parser = new SpelExpressionParser();

 

// invokes 'getBytes().length'

// 调用getBytes().length

Expression exp = parser.parseExpression("'Hello World'.bytes.length");

int length = (Integer) exp.getValue();

 

The String’s constructor can be called instead of using a string literal.

字符串的构造器可以通过使用文本方式来进行替代

 

ExpressionParser parser = new SpelExpressionParser();

Expression exp = parser.parseExpression("new String('hello world').toUpperCase()");

String message = exp.getValue(String.class);

 

Note the use of the generic method public <T> T getValue(Class<T> desiredResultType). Using this method removes the need to cast the value of the expression to the desired result type. An EvaluationException will be thrown if the value cannot be cast to the type T or converted using the registered type converter.

注意通用的方法public <T> T getValue(Class<T> desiredResultType)的使用。使用这样的方法去掉了将表达式的值转换为目标的结果类型。如果值不能转化为T类型或转换使用了注册的类型转换器将抛出EvaluationException异常。

 

The more common usage of SpEL is to provide an expression string that is evaluated against a specific object instance (called the root object). There are two options here and which to choose depends on whether the object against which the expression is being evaluated will be changing with each call to evaluate the expression. In the following example we retrieve the name property from an instance of the Inventor class.

通常使用SpEL是用于提供一个表达式字符串处理特定的object实例(叫做root object)。这里有两种方法可以选择依赖于被处理的object在使用时是否会改变在调用表达式的时候。在下面的例子中我们获得了Inventor类中的name属性。

 

// Create and set a calendar

// 创建并设置一个calendar

GregorianCalendar c = new GregorianCalendar();

c.set(1856, 7, 9);

 

// The constructor arguments are name, birthday, and nationality.

// 构造器属性是name、birthday、nationality

Inventor tesla = new Inventor("Nikola Tesla", c.getTime(), "Serbian");

 

ExpressionParser parser = new SpelExpressionParser();

Expression exp = parser.parseExpression("name");

 

EvaluationContext context = new StandardEvaluationContext(tesla);

String name = (String) exp.getValue(context);

 

In the last line, the value of the string variable name will be set to "Nikola Tesla". The class StandardEvaluationContext is where you can specify which object the "name" property will be evaluated against. This is the mechanism to use if the root object is unlikely to change, it can simply be set once in the evaluation context. If the root object is likely to change repeatedly, it can be supplied on each call to getValue, as this next example shows:

在最后一行,字符串变量name的值是"Nikola Tesla"。使用StandardEvaluationContext你可以处理name属性的值。如果root object没有被改变过时的一种策略,可以在上下文中直接设置。如果root object的值反复被改变,可以类似于下面例子的说明调用getValue:

 

// Create and set a calendar

// 创建并设置一个calendar

GregorianCalendar c = new GregorianCalendar();

c.set(1856, 7, 9);

 

// The constructor arguments are name, birthday, and nationality.

// 构造器参数是name、birthday和nationality

Inventor tesla = new Inventor("Nikola Tesla", c.getTime(), "Serbian");

 

ExpressionParser parser = new SpelExpressionParser();

Expression exp = parser.parseExpression("name");

String name = (String) exp.getValue(tesla);

 

In this case the inventor tesla has been supplied directly to getValue and the expression evaluation infrastructure creates and manages a default evaluation context internally - it did not require one to be supplied.

在这个例子中使用inventor tesla来直接调用getValue和表达式处理创建和管理默认的上下文则不需要被提供。

 

The StandardEvaluationContext is relatively expensive to construct and during repeated usage it builds up cached state that enables subsequent expression evaluations to be performed more quickly. For this reason it is better to cache and reuse them where possible, rather than construct a new one for each expression evaluation.

StandardEvaluationContext的创建是比较消耗资源,并且在重复使用中会产生缓存状态允许后面的表达式可以迅速得到处理。在这种情况下最好根据需要缓存和重复使用他们而不是在每个表达式处理中创建一个新实例。

 

In some cases it can be desirable to use a configured evaluation context and yet still supply a different root object on each call to getValue. getValue allows both to be specified on the same call. In these situations the root object passed on the call is considered to override any (which maybe null) specified on the evaluation context.

在一些情况下可以使用配置上下文和提供不同的root object在每次调用getValue时。getValue允许在同一次调用中进行定制化。在这些情况下,被调用的root object覆盖任何特定一项(或许是null)在上下文中。

 

[Note]

注意

 

In standalone usage of SpEL there is a need to create the parser, parse expressions and perhaps provide evaluation contexts and a root context object. However, more common usage is to provide only the SpEL expression string as part of a configuration file, for example for Spring bean or Spring Web Flow definitions. In this case, the parser, evaluation context, root object and any predefined variables are all set up implicitly, requiring the user to specify nothing other than the expressions.

单独使用SpEL需要创建解析器,解析表达式和提供上下文和root上下文object。然而,大部分情况下只有SpEL表达式作为配置文件的一部分,例如对于spring的bean或spring的web流定义。在这些情况下,解析器、上下文、root object和其他提前定义的变量都被隐含的设置,需要用户定义表达式而不需要定义其他内容。

 

As a final introductory example, the use of a boolean operator is shown using the Inventor object in the previous example.

作为最后一个例子,使用了boolean表达式用于展示在前面的例子中使用Inventor的object。

 

Expression exp = parser.parseExpression("name == 'Nikola Tesla'");

boolean result = exp.getValue(context, Boolean.class); // evaluates to true

 

10.3.1 The EvaluationContext interface

EvaluationContext接口

 

The interface EvaluationContext is used when evaluating an expression to resolve properties, methods, fields, and to help perform type conversion. The out-of-the-box implementation, StandardEvaluationContext, uses reflection to manipulate the object, caching java.lang.reflect.Method, java.lang.reflect.Field, and java.lang.reflect.Constructor instances for increased performance.

EvaluationContext接口处理表达式用于处理属性、方法、域和帮助提供类型转换。外部的实现有StandardEvaluationContext使用反射来处理object,调用java.lang.reflect.Method、java.lang.reflect.Field和java.lang.reflect.Constructor实例用于提高性能。

 

The StandardEvaluationContext is where you may specify the root object to evaluate against via the method setRootObject() or passing the root object into the constructor. You can also specify variables and functions that will be used in the expression using the methods setVariable() and registerFunction(). The use of variables and functions are described in the language reference sections Variables and Functions. The StandardEvaluationContext is also where you can register custom ConstructorResolvers, MethodResolvers, and PropertyAccessors to extend how SpEL evaluates expressions. Please refer to the JavaDoc of these classes for more details.

StandardEvaluationContext你可以用来指定root object来处理通过setRootObject方法或将root object传递给构造器。你也可以指定变量和函数使用在表达式中通过方法setVariable和registerFunction。变量和函数的使用在语言参考文档章节名是变量和函数。StandardEvaluationContext也可以用来注册自定义的ConstructorResolvers、MethodResolvers和PropertyAccessors用来扩展SpEL处理表达式。请参考Javadocs获取更多信息。

 

Type Conversion

类型转换

 

By default SpEL uses the conversion service available in Spring core ( org.springframework.core.convert.ConversionService). This conversion service comes with many converters built in for common conversions but is also fully extensible so custom conversions between types can be added. Additionally it has the key capability that it is generics aware. This means that when working with generic types in expressions, SpEL will attempt conversions to maintain type correctness for any objects it encounters.

通过默认的SpEL使用转换服务在spring core中是可行的(org.springframework.core.convert.ConversionService)。转换服务由内置的多个转换器来支持用于通用的转换但是也支持扩展使得自定义转换器可以被添加。额外的,也支持关键字识别。这意味着可以在表达式中使用泛型,SpEL将会尝试转换类型的准确性对于处理的任何object。

 

What does this mean in practice? Suppose assignment, using setValue(), is being used to set a List property. The type of the property is actually List<Boolean>. SpEL will recognize that the elements of the list need to be converted to Boolean before being placed in it. A simple example:

在练习这意味着什么?假设分配属性,使用setValue,可以用于设置一个list属性。属性的类型实际上是List<Boolean>。SpEL将会识别到list中元素的类型需要转换为Boolean在其被放置到list中之前。一个简单的例子:

 

class Simple {

    public List<Boolean> booleanList = new ArrayList<Boolean>();

}

 

Simple simple = new Simple();

 

simple.booleanList.add(true);

 

StandardEvaluationContext simpleContext = new StandardEvaluationContext(simple);

 

// false is passed in here as a string. SpEL and the conversion service will

// correctly recognize that it needs to be a Boolean and convert it

// false在这里通过字符串的形式传递。SpEL和转换服务将正确识别到需要转换为boolean然后进行转换

parser.parseExpression("booleanList[0]").setValue(simpleContext, "false");

 

// b will be false

// b的值是false

Boolean b = simple.booleanList.get(0);

 

10.3.2 Parser configuration

解析器配置

 

It is possible to configure the SpEL expression parser using a parser configuration object (org.springframework.expression.spel.SpelParserConfiguration). The configuration object controls the behavior of some of the expression components. For example, if indexing into an array or collection and the element at the specified index is null it is possible to automatically create the element. This is useful when using expressions made up of a chain of property references. If indexing into an array or list and specifying an index that is beyond the end of the current size of the array or list it is possible to automatically grow the array or list to accommodate that index.

配置SpEL表达式解析器通过使用一个解析器配置object是可以的(org.springframework.expression.spel.SpelParserConfiguration)。配置object控制一些表达式组件的行为。例如,如果在数组或集合中索引,元素在特定的索引是null可以自动创建元素。当使用表达式组成属性引用链时这种方式是有用的。如果在数组或list中索引,并且指定索引取决于当前数组或list的大小的结尾可以自动增加直到索引的末尾。

 

class Demo {

    public List<String> list;

}

 

// Turn on:

// - auto null reference initialization

// 自动null引用初始化

// - auto collection growing

// 自动集合增长

SpelParserConfiguration config = new SpelParserConfiguration(true,true);

 

ExpressionParser parser = new SpelExpressionParser(config);

 

Expression expression = parser.parseExpression("list[3]");

 

Demo demo = new Demo();

 

Object o = expression.getValue(demo);

 

// demo.list will now be a real collection of 4 entries

// demo.list现在是一个用于4个元素的集合

// Each entry is a new empty String

// 每个元素是一个空的字符串

 

It is also possible to configure the behaviour of the SpEL expression compiler.

也可以配置SpEL表达式编译器的行为

 

10.3.3 SpEL compilation

SpEL编译

 

Spring Framework 4.1 includes a basic expression compiler. Expressions are usually interpreted which provides a lot of dynamic flexibility during evaluation but does not provide the optimum performance. For occasional expression usage this is fine, but when used by other components like Spring Integration, performance can be very important and there is no real need for the dynamism.

spring框架4.1包括基本的表达式编译器。表达式通常被理解通过提供许多动柔度在处理过程中但是不提供性能的操作性。对于偶然的表达式使用也是可以的,但是当用于其他的组件例如spring集成时,性能将会很重要并且不需要动态的特性的。

 

The new SpEL compiler is intended to address this need. The compiler will generate a real Java class on the fly during evaluation that embodies the expression behavior and use that to achieve much faster expression evaluation. Due to the lack of typing around expressions the compiler uses information gathered during the interpreted evaluations of an expression when performing compilation. For example, it does not know the type of a property reference purely from the expression but during the first interpreted evaluation it will find out what it is. Of course, basing the compilation on this information could cause trouble later if the types of the various expression elements change over time. For this reason compilation is best suited to expressions whose type information is not going to change on repeated evaluations.

新的SpEL编译器试图满足这样的需要。编译器将会生成一个实际的Java类在处理期间并体现了表达式行为并且可以获得更快的表达式处理速度。由于缺少输入的表达式编译器使用信息收集当处理编译表达式的过程中。例如,不需要知道属性的类型引用通过表达式但是在第一次处理时找到。当然,基于编译这些信息可能会在后续引起问题如果不同表达式元素发生了改变。由于这种原因编译是最适合表达类型的信息而不需要在重复的评估中改变。

 

For a basic expression like this:

对于一个基本的表达式如下:

 

someArray[0].someProperty.someOtherProperty < 0.1

 

which involves array access, some property derefencing and numeric operations, the performance gain can be very noticeable. In an example micro benchmark run of 50000 iterations, it was taking 75ms to evaluate using only the interpreter and just 3ms using the compiled version of the expression.

调用数组访问、属性的间接引用和数字的操作,性能的提升是显而易见的。在一个例子中微机分数运行5万次迭代,只花费了75毫秒来拦截并且只有3毫秒用于编译表达式的版本。

 

Compiler configuration

编译器配置

 

The compiler is not turned on by default, but there are two ways to turn it on. It can be turned on using the parser configuration process discussed earlier or via a system property when SpEL usage is embedded inside another component. This section discusses both of these options.

编译器在默认情况下并没有开启,但是有两种方式来打开它。可以使用解析配置进程在前面讨论过的或通过系统属性当SpEL使用在另一个内置的组件中。这一节将讨论这三个选项。

 

Is is important to understand that there are a few modes the compiler can operate in, captured in an enum (org.springframework.expression.spel.SpelCompilerMode). The modes are as follows:

理解有一些模式可以让编译器操作是重要的,设置在枚举中(org.springframework.expression.spel.SpelCompilerMode)。这些模式包括:

 

    OFF - The compiler is switched off; this is the default.

OFF - 编译器是关闭的,这是默认值

    IMMEDIATE - In immediate mode the expressions are compiled as soon as possible. This is typically after the first interpreted evaluation. If the compiled expression fails (typically due to a type changing, as described above) then the caller of the expression evaluation will receive an exception.

IMMEDIATE - 在这个模式下表达式会以最快的速度编译。通常在第一次运行之后。如果编译表达式失败(通常由于类型改变,在上面描述过)然后调用表达式会收到一个异常。

    MIXED - In mixed mode the expressions silently switch between interpreted and compiled mode over time. After some number of interpreted runs they will switch to compiled form and if something goes wrong with the compiled form (like a type changing, as described above) then the expression will automatically switch back to interpreted form again. Sometime later it may generate another compiled form and switch to it. Basically the exception that the user gets in IMMEDIATE mode is instead handled internally.

MIXED - 在这个模式下表达式会安静的切换在理解和编译模式间。在一些拦截器运行后他们将会转换编译形式并且如果一些问题在编译中产生(例如类型改变,在上面描述过)表达式将会再一次自动切换回拦截。有时可能会产生另一种编译形式然后转换至此。基本用户获得的异常在IMMEDIATE模式会在内部被处理。

 

IMMEDIATE mode exists because MIXED mode could cause issues for expressions that have side effects. If a compiled expression blows up after partially succeeding it may have already done something that has affected the state of the system. If this has happened the caller may not want it to silently re-run in interpreted mode since part of the expression may be running twice.

IMMEDIATE模式存在是因为MIXED模式在处理表达式时可能产生问题并有其他的影响。如果一个编译表达式在部分成功的情况下,可能已经影响了系统的某些状态。如果已经出现这种情况,调用者可能不希望重新执行程序因为有些有些表达式可能会运行两次。

 

After selecting a mode, use the SpelParserConfiguration to configure the parser:

当选择一种模式后,使用SpelParserConfiguration来配置解析器:

 

SpelParserConfiguration config = new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE,

    this.getClass().getClassLoader());

 

SpelExpressionParser parser = new SpelExpressionParser(config);

 

Expression expr = parser.parseExpression("payload");

 

MyMessage message = new MyMessage();

 

Object payload = expr.getValue(message);

 

When specifying the compiler mode it is also possible to specify a classloader (passing null is allowed). Compiled expressions will be defined in a child classloader created under any that is supplied. It is important to ensure if a classloader is specified it can see all the types involved in the expression evaluation process. If none is specified then a default classloader will be used (typically the context classloader for the thread that is running during expression evaluation).

当指定编译器模式时也可以指定一个类加载器(传递null也是允许的)。编译表达式将会被定义在被提供的子类加载器中创建。如果定义了一个类加载器确保他可以看到所有表达式处理的所有类型是很重要的。如果没有定义则默认的类加载器将会被使用(通常用于线程的上下文加载器在表达式处理时会执行)

 

The second way to configure the compiler is for use when SpEL is embedded inside some other component and it may not be possible to configure via a configuration object. In these cases it is possible to use a system property. The property spring.expression.compiler.mode can be set to one of the SpelCompilerMode enum values (off, immediate, or mixed).

第二个方法配置编译器是为了用于当SpEL被嵌入到其他的组件并且可能不能通过configuration来配置。在这种情况下可以使用系统属性。spring.expression.compiler.mode属性可以被设置为SpelCompilerMode的其中一个枚举值(off、immediate或mixed)

 

Compiler limitations

编译器限制

 

With Spring Framework 4.1 the basic compilation framework is in place. However, the framework does not yet support compiling every kind of expression. The initial focus has been on the common expressions that are likely to be used in performance critical contexts. These kinds of expression cannot be compiled at the moment:

在spring框架4.1中有基本的编译框架。然而,框架不支持编译每一种表达式。重点会关注在通用的表达式可以在一些严酷性能的上下文中运行。这是这些表达式不能被编译:

 

    expressions involving assignment

用于分配的表达式

    expressions relying on the conversion service

依赖转换服务的表达式

    expressions using custom resolvers or accessors

使用自定义解析器或访问器的表达式

    expressions using selection or projection

使用选择或映射的表达式

 

More and more types of expression will be compilable in the future.

在未来越来越多类型的表达式将会被编译。

 

10.4 Expression support for defining bean definitions

用于定义bean定义的表达式支持

 

SpEL expressions can be used with XML or annotation-based configuration metadata for defining BeanDefinitions. In both cases the syntax to define the expression is of the form #{ <expression string> }.

SpEL表达式可以通过XML或基于注解的配置用于定义bean定义。在相同的情况下定义表达式的语法类似于#{<表达式字符串>}

 

10.4.1 XML based configuration

基于xml的配置

 

A property or constructor-arg value can be set using expressions as shown below.

属性或构造器参数值可以被设置用于表达式,例子如下。

 

<bean id="numberGuess" class="org.spring.samples.NumberGuess">

    <property name="randomNumber" value="#{ T(java.lang.Math).random() * 100.0 }"/>

 

    <!-- other properties -->

</bean>

 

The variable systemProperties is predefined, so you can use it in your expressions as shown below. Note that you do not have to prefix the predefined variable with the # symbol in this context.

systemProperties之前已经定义,因此你可以如下使用你的表达式。注意你不能在之前定义的变量前增加前缀#在上下文中。

 

<bean id="taxCalculator" class="org.spring.samples.TaxCalculator">

    <property name="defaultLocale" value="#{ systemProperties['user.region'] }"/>

 

    <!-- other properties -->

</bean>

 

You can also refer to other bean properties by name, for example.

你也可以通过name引用其他的bean属性,例如。

 

<bean id="numberGuess" class="org.spring.samples.NumberGuess">

    <property name="randomNumber" value="#{ T(java.lang.Math).random() * 100.0 }"/>

 

    <!-- other properties -->

</bean>

 

<bean id="shapeGuess" class="org.spring.samples.ShapeGuess">

    <property name="initialShapeSeed" value="#{ numberGuess.randomNumber }"/>

 

    <!-- other properties -->

</bean>

 

10.4.2 Annotation-based configuration

基于注解的配置

 

The @Value annotation can be placed on fields, methods and method/constructor parameters to specify a default value.

@Value注解可以修饰属性、方法、方法/构造方法参数用于定义默认值。

 

Here is an example to set the default value of a field variable.

下面是一个为属性设置默认值的例子。

 

public static class FieldValueTestBean

 

    @Value("#{ systemProperties['user.region'] }")

    private String defaultLocale;

 

    public void setDefaultLocale(String defaultLocale) {

        this.defaultLocale = defaultLocale;

    }

 

    public String getDefaultLocale() {

        return this.defaultLocale;

    }

 

}

 

The equivalent but on a property setter method is shown below.

相同但是下面的例子是修饰在属性的set方法上。

 

public static class PropertyValueTestBean

 

    private String defaultLocale;

 

    @Value("#{ systemProperties['user.region'] }")

    public void setDefaultLocale(String defaultLocale) {

        this.defaultLocale = defaultLocale;

    }

 

    public String getDefaultLocale() {

        return this.defaultLocale;

    }

 

}

 

Autowired methods and constructors can also use the @Value annotation.

使用@Autowired方法在构造方法中也可以使用@Value注解

 

public class SimpleMovieLister {

 

    private MovieFinder movieFinder;

    private String defaultLocale;

 

    @Autowired

    public void configure(MovieFinder movieFinder,

            @Value("#{ systemProperties['user.region'] }") String defaultLocale) {

        this.movieFinder = movieFinder;

        this.defaultLocale = defaultLocale;

    }

 

    // ...

}

 

public class MovieRecommender {

 

    private String defaultLocale;

 

    private CustomerPreferenceDao customerPreferenceDao;

 

    @Autowired

    public MovieRecommender(CustomerPreferenceDao customerPreferenceDao,

            @Value("#{systemProperties['user.country']}") String defaultLocale) {

        this.customerPreferenceDao = customerPreferenceDao;

        this.defaultLocale = defaultLocale;

    }

 

    // ...

}

 

10.5 Language Reference

语言参考

 

10.5.1 Literal expressions

轻量级表达式

 

The types of literal expressions supported are strings, dates, numeric values (int, real, and hex), boolean and null. Strings are delimited by single quotes. To put a single quote itself in a string use two single quote characters. The following listing shows simple usage of literals. Typically they would not be used in isolation like this, but as part of a more complex expression, for example using a literal on one side of a logical comparison operator.

轻量级表达式类型支持字符串、日期、数值(int、real和hex)、布尔值和null。字符串使用单引号定义。为了加入单引号需要使用两个双引号字符。下面的列子展示了使用方法。通常不会孤立的被使用如下,但是作为一个复杂表达式的一部分,例如使用轻量级作为逻辑比较符的一边。

 

ExpressionParser parser = new SpelExpressionParser();

 

// evals to "Hello World"

// 与“Hello World”相同

String helloWorld = (String) parser.parseExpression("'Hello World'").getValue();

 

double avogadrosNumber = (Double) parser.parseExpression("6.0221415E+23").getValue();

 

// evals to 2147483647

// 与2147483647相同

int maxValue = (Integer) parser.parseExpression("0x7FFFFFFF").getValue();

 

boolean trueValue = (Boolean) parser.parseExpression("true").getValue();

 

Object nullValue = parser.parseExpression("null").getValue();

 

Numbers support the use of the negative sign, exponential notation, and decimal points. By default real numbers are parsed using Double.parseDouble().

数值支持使用负号、指数记法和小数点。默认数值会通过Double.parseDouble()来解析。

 

10.5.2 Properties, Arrays, Lists, Maps, Indexers

Properties、数组、List、Map和索引器

 

Navigating with property references is easy: just use a period to indicate a nested property value. The instances of the Inventor class, pupin, and tesla, were populated with data listed in the section Classes used in the examples. To navigate "down" and get Tesla’s year of birth and Pupin’s city of birth the following expressions are used.

调用属性的引用是简单的:只要指定内置的属性值就可以。Inventor类的实例、pupin和tesla列在10.6节中。下面的表达式用于获得Tesla的出生年和Pupin的出生城市。

 

// evals to 1856

int year = (Integer) parser.parseExpression("Birthdate.Year + 1900").getValue(context);

 

String city = (String) parser.parseExpression("placeOfBirth.City").getValue(context);

 

Case insensitivity is allowed for the first letter of property names. The contents of arrays and lists are obtained using square bracket notation.

对于属性名的第一个字母的大小写不是必须的要求。对于数组和list的内容可以使用方括号下标的形式。

 

ExpressionParser parser = new SpelExpressionParser();

 

// Inventions Array

StandardEvaluationContext teslaContext = new StandardEvaluationContext(tesla);

 

// evaluates to "Induction motor"

String invention = parser.parseExpression("inventions[3]").getValue(

        teslaContext, String.class);

 

// Members List

StandardEvaluationContext societyContext = new StandardEvaluationContext(ieee);

 

// evaluates to "Nikola Tesla"

String name = parser.parseExpression("Members[0].Name").getValue(

        societyContext, String.class);

 

// List and Array navigation

// evaluates to "Wireless communication"

String invention = parser.parseExpression("Members[0].Inventions[6]").getValue(

        societyContext, String.class);

 

The contents of maps are obtained by specifying the literal key value within the brackets. In this case, because keys for the Officers map are strings, we can specify string literals.

maps的内容通过方括号包围的文字的key值定义。因此,因为Officers的keys是字符串,我们可以定义字符字面值。

 

// Officer's Dictionary

 

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);

 

// setting values

parser.parseExpression("Officers['advisors'][0].PlaceOfBirth.Country").setValue(

        societyContext, "Croatia");

 

10.5.3 Inline lists

内部的list

 

Lists can be expressed directly in an expression using {} notation.

list可以直接通过{}来表示。

 

// evaluates to a Java list containing the four numbers

// 等同于定义了一个有四个元素的java的list

List numbers = (List) parser.parseExpression("{1,2,3,4}").getValue(context);

 

List listOfLists = (List) parser.parseExpression("{{'a','b'},{'x','y'}}").getValue(context);

 

{} by itself means an empty list. For performance reasons, if the list is itself entirely composed of fixed literals then a constant list is created to represent the expression, rather than building a new list on each evaluation.

{}本身意味着一个空的list。处于性能的考虑,如果list本身是由固定的字面值,一个常量的list可以通过一个表达式来创建,而不是每次创建一个新的list。

 

10.5.4 Inline Maps

内联的maps

 

Maps can also be expressed directly in an expression using {key:value} notation.

maps也可以直接使用{key:value}的形式通过表达式来定义。

 

// evaluates to a Java map containing the two entries

// 相当于一个包含两个元素的java的map

Map inventorInfo = (Map) parser.parseExpression("{name:'Nikola',dob:'10-July-1856'}").getValue(context);

 

Map mapOfMaps = (Map) parser.parseExpression("{name:{first:'Nikola',last:'Tesla'},dob:{day:10,month:'July',year:1856}}").getValue(context);

 

{:} by itself means an empty map. For performance reasons, if the map is itself composed of fixed literals or other nested constant structures (lists or maps) then a constant map is created to represent the expression, rather than building a new map on each evaluation. Quoting of the map keys is optional, the examples above are not using quoted keys.

{:}本身是一个空的map。出于性能的考虑,如果map自身是由固定的字面量或其他内嵌的常量结构(list或map)最好通过表达式创建,比每次创建一个新的map要好。map的双引号是可选的,例子中没有使用双引号的key。

 

10.5.5 Array construction

数组的构造

 

Arrays can be built using the familiar Java syntax, optionally supplying an initializer to have the array populated at construction time.

数组可以通过使用类似的java语法来创建,可以在构造时提供一个创建数组的初始化器。

 

int[] numbers1 = (int[]) parser.parseExpression("new int[4]").getValue(context);

 

// Array with initializer

int[] numbers2 = (int[]) parser.parseExpression("new int[]{1,2,3}").getValue(context);

 

// Multi dimensional array

int[][] numbers3 = (int[][]) parser.parseExpression("new int[4][5]").getValue(context);

 

It is not currently allowed to supply an initializer when constructing a multi-dimensional array.

目前不支持创建多维数组的初始化器。

 

10.5.6 Methods

方法

 

Methods are invoked using typical Java programming syntax. You may also invoke methods on literals. Varargs are also supported.

通过java语法可以调用方法。你也可以以字面的方式调用方法。支持可变参数。

 

// string literal, evaluates to "bc"

// 字符串字面量,相当于'bc'

String c = parser.parseExpression("'abc'.substring(2, 3)").getValue(String.class);

 

// evaluates to true

boolean isMember = parser.parseExpression("isMember('Mihajlo Pupin')").getValue(

        societyContext, Boolean.class);

 

10.5.7 Operators

操作符

 

Relational operators

关系操作符

 

The relational operators; equal, not equal, less than, less than or equal, greater than, and greater than or equal are supported using standard operator notation.

关系操作符:相等、不等、小于、小于等于、大于、大于等于可以通过使用标准的操作符被支持。

 

// evaluates to true

boolean trueValue = parser.parseExpression("2 == 2").getValue(Boolean.class);

 

// evaluates to false

boolean falseValue = parser.parseExpression("2 < -5.0").getValue(Boolean.class);

 

// evaluates to true

boolean trueValue = parser.parseExpression("'black' < 'block'").getValue(Boolean.class);

 

In addition to standard relational operators SpEL supports the instanceof and regular expression based matches operator.

除了标准的关系操作符外,SpEL支持instanceof和正则表达式基于matchs操作符。

 

// evaluates to false

boolean falseValue = parser.parseExpression(

        "'xyz' instanceof T(Integer)").getValue(Boolean.class);

 

// evaluates to true

boolean trueValue = parser.parseExpression(

        "'5.00' matches '/^-?//d+(//.//d{2})?$'").getValue(Boolean.class);

 

//evaluates to false

boolean falseValue = parser.parseExpression(

        "'5.0067' matches '/^-?//d+(//.//d{2})?$'").getValue(Boolean.class);

 

[Note]

注意

 

Be careful with primitive types as they are immediately boxed up to the wrapper type, so 1 instanceof T(int) evaluates to false while 1 instanceof T(Integer) evaluates to true, as expected.

使用原始类型的时候小心他们直接被包装成包装类,因此1 instanceof T(int)是false的而1 instanceof T(Integer)是true。

 

Each symbolic operator can also be specified as a purely alphabetic equivalent. This avoids problems where the symbols used have special meaning for the document type in which the expression is embedded (eg. an XML document). The textual equivalents are shown here: lt (<), gt (>), le (?), ge (>=), eq (==), ne (!=), div (/), mod (%), not (!). These are case insensitive.

每一个符号操作符可以使用直接的单词首字母来定义。这样可以避免在某些特定的表达式会在文件类型中出现问题(比如xml)。现在列出文本的替换规则:lt (<), gt (>), le (?), ge (>=), eq (==), ne (!=), div (/), mod (%), not (!)。他们是不区分大小写的。

 

Logical operators

逻辑操作符

 

The logical operators that are supported are and, or, and not. Their use is demonstrated below.

支持逻辑操作符and、or和not。使用方法如下:

 

// -- AND --

 

// evaluates to false

boolean falseValue = parser.parseExpression("true and false").getValue(Boolean.class);

 

// evaluates to true

String expression = "isMember('Nikola Tesla') and isMember('Mihajlo Pupin')";

boolean trueValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class);

 

// -- OR --

 

// evaluates to true

boolean trueValue = parser.parseExpression("true or false").getValue(Boolean.class);

 

// evaluates to true

String expression = "isMember('Nikola Tesla') or isMember('Albert Einstein')";

boolean trueValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class);

 

// -- NOT --

 

// evaluates to false

boolean falseValue = parser.parseExpression("!true").getValue(Boolean.class);

 

// -- AND and NOT --

String expression = "isMember('Nikola Tesla') and !isMember('Mihajlo Pupin')";

boolean falseValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class);

 

Mathematical operators

算术操作符

 

The addition operator can be used on both numbers and strings. Subtraction, multiplication and division can be used only on numbers. Other mathematical operators supported are modulus (%) and exponential power (^). Standard operator precedence is enforced. These operators are demonstrated below.

加法可以用在数值和字符串之间。减法、乘法和除法只能用在数值之间。其他算术操作符支持取余和乘方。标准的运算符是支持优先级的。例子如下:

 

// Addition

int two = parser.parseExpression("1 + 1").getValue(Integer.class); // 2

 

String testString = parser.parseExpression(

        "'test' + ' ' + 'string'").getValue(String.class); // 'test string'

 

// Subtraction

int four = parser.parseExpression("1 - -3").getValue(Integer.class); // 4

 

double d = parser.parseExpression("1000.00 - 1e4").getValue(Double.class); // -9000

 

// Multiplication

int six = parser.parseExpression("-2 * -3").getValue(Integer.class); // 6

 

double twentyFour = parser.parseExpression("2.0 * 3e0 * 4").getValue(Double.class); // 24.0

 

// Division

int minusTwo = parser.parseExpression("6 / -3").getValue(Integer.class); // -2

 

double one = parser.parseExpression("8.0 / 4e0 / 2").getValue(Double.class); // 1.0

 

// Modulus

int three = parser.parseExpression("7 % 4").getValue(Integer.class); // 3

 

int one = parser.parseExpression("8 / 5 % 2").getValue(Integer.class); // 1

 

// Operator precedence

int minusTwentyOne = parser.parseExpression("1+2-3*8").getValue(Integer.class); // -21

 

10.5.8 Assignment

分配

 

Setting of a property is done by using the assignment operator. This would typically be done within a call to setValue but can also be done inside a call to getValue.

属性的设置是通过赋值操作符。通常会叫做设置值也可以getValue来实现。

 

Inventor inventor = new Inventor();

StandardEvaluationContext inventorContext = new StandardEvaluationContext(inventor);

 

parser.parseExpression("Name").setValue(inventorContext, "Alexander SEOvic2");

 

// alternatively

// 或者使用下面的方法

 

String aleks = parser.parseExpression(

        "Name = 'Alexandar Seovic'").getValue(inventorContext, String.class);

 

10.5.9 Types

类型

 

The special T operator can be used to specify an instance of java.lang.Class (the type). Static methods are invoked using this operator as well. The StandardEvaluationContext uses a TypeLocator to find types and the StandardTypeLocator (which can be replaced) is built with an understanding of the java.lang package. This means T() references to types within java.lang do not need to be fully qualified, but all other type references must be.

特殊的T操作符用于定义一个类的实例。也可以使用该操作符调用静态方法。StandardEvaluationContext使用TypeLocator来查找类型和创建StandardTypeLocator(被替换)来累计额java.lang包。这意味着T代表java.lang的类型不需要类的全限定名,但是其他的类型引用需要。

 

Class dateClass = parser.parseExpression("T(java.util.Date)").getValue(Class.class);

 

Class stringClass = parser.parseExpression("T(String)").getValue(Class.class);

 

boolean trueValue = parser.parseExpression(

        "T(java.math.RoundingMode).CEILING < T(java.math.RoundingMode).FLOOR")

        .getValue(Boolean.class);

 

10.5.10 Constructors

构造器

 

Constructors can be invoked using the new operator. The fully qualified class name should be used for all but the primitive type and String (where int, float, etc, can be used).

构造器可以使用新的操作符来调用。除了基本类型和String外需要使用全限定类名(int、float等等是可以直接使用的)

 

Inventor einstein = p.parseExpression(

        "new org.spring.samples.spel.inventor.Inventor('Albert Einstein', 'German')")

        .getValue(Inventor.class);

 

//create new inventor instance within add method of List

p.parseExpression(

        "Members.add(new org.spring.samples.spel.inventor.Inventor(

            'Albert Einstein', 'German'))").getValue(societyContext);

 

10.5.11 Variables

变量

 

Variables can be referenced in the expression using the syntax #variableName. Variables are set using the method setVariable on the StandardEvaluationContext.

变量可以在表达式中通过#variableName来表示。变量的设置使用StandardEvaluationContext的setVariable方法。

 

Inventor tesla = new Inventor("Nikola Tesla", "Serbian");

StandardEvaluationContext context = new StandardEvaluationContext(tesla);

context.setVariable("newName", "Mike Tesla");

 

parser.parseExpression("Name = #newName").getValue(context);

 

System.out.println(tesla.getName()) // "Mike Tesla"

 

The #this and #root variables

#this和#root变量

 

The variable #this is always defined and refers to the current evaluation object (against which unqualified references are resolved). The variable #root is always defined and refers to the root context object. Although #this may vary as components of an expression are evaluated, #root always refers to the root.

#this变量始终指向当前的object(处理没有全限定的引用)。#root变量使用指向根上下文object。尽管#this可能根据表达式而不同,但是#root一直指向根。

 

// create an array of integers

List<Integer> primes = new ArrayList<Integer>();

primes.addAll(Arrays.asList(2,3,5,7,11,13,17));

 

// create parser and set variable 'primes' as the array of integers

ExpressionParser parser = new SpelExpressionParser();

StandardEvaluationContext context = new StandardEvaluationContext();

context.setVariable("primes",primes);

 

// all prime numbers > 10 from the list (using selection ?{...})

// evaluates to [11, 13, 17]

List<Integer> primesGreaterThanTen = (List<Integer>) parser.parseExpression(

        "#primes.?[#this>10]").getValue(context);

 

10.5.12 Functions

函数

 

You can extend SpEL by registering user defined functions that can be called within the expression string. The function is registered with the StandardEvaluationContext using the method.

你可以通过用户自定义函数来扩展SpEL可以在表达式字符串中使用。函数使用StandardEvaluationContext的方法来注册。

 

public void registerFunction(String name, Method m)

 

A reference to a Java Method provides the implementation of the function. For example, a utility method to reverse a string is shown below.

java方法的引用提供了函数的实现。例如,一个翻转字符串的方法实现如下。

 

public abstract class StringUtils {

 

    public static String reverseString(String input) {

        StringBuilder backwards = new StringBuilder();

        for (int i = 0; i < input.length(); i++)

            backwards.append(input.charAt(input.length() - 1 - i));

        }

        return backwards.toString();

    }

}

 

This method is then registered with the evaluation context and can be used within an expression string.

这个方法注册在上下文中可以如下使用。

 

ExpressionParser parser = new SpelExpressionParser();

StandardEvaluationContext context = new StandardEvaluationContext();

 

context.registerFunction("reverseString",

    StringUtils.class.getDeclaredMethod("reverseString", new Class[] { String.class }));

 

String helloWorldReversed = parser.parseExpression(

    "#reverseString('hello')").getValue(context, String.class);

 

10.5.13 Bean references

bean的引用

 

If the evaluation context has been configured with a bean resolver it is possible to lookup beans from an expression using the (@) symbol.

如果评价上下文通过一个bean的解析器被配置,就可以从使用@标识符的表达式中查找bean。

 

ExpressionParser parser = new SpelExpressionParser();

StandardEvaluationContext context = new StandardEvaluationContext();

context.setBeanResolver(new MyBeanResolver());

 

// This will end up calling resolve(context,"foo") on MyBeanResolver during evaluation

// 这样会在处理时调用MyBeanResolver的resolve(context,"foo")

Object bean = parser.parseExpression("@foo").getValue(context);

 

To access a factory bean itself, the bean name should instead be prefixed with a (&) symbol.

为了访问工厂bean本身,bean的名字前应该使用&符号。

 

ExpressionParser parser = new SpelExpressionParser();

StandardEvaluationContext context = new StandardEvaluationContext();

context.setBeanResolver(new MyBeanResolver());

 

// This will end up calling resolve(context,"&foo") on MyBeanResolver during evaluation

// 这样会在处理时调用MyBeanResolver的resolve(context,"&foo")

Object bean = parser.parseExpression("&foo").getValue(context);

 

10.5.14 Ternary Operator (If-Then-Else)

三元操作符(If-Then-Else)

 

You can use the ternary operator for performing if-then-else conditional logic inside the expression. A minimal example is:

你可以在表达式中使用三元操作符实现if-then-else的逻辑。一个小例子如下:

 

String falseString = parser.parseExpression(

        "false ? 'trueExp' : 'falseExp'").getValue(String.class);

 

In this case, the boolean false results in returning the string value 'falseExp'. A more realistic example is shown below.

在这个例子中,布尔的false值将返回'falseExp'字符串。一个比较复杂的例子如下。

 

parser.parseExpression("Name").setValue(societyContext, "IEEE");

societyContext.setVariable("queryName", "Nikola Tesla");

 

expression = "isMember(#queryName)? #queryName + ' is a member of the ' " +

        "+ Name + ' Society' : #queryName + ' is not a member of the ' + Name + ' Society'";

 

String queryResultString = parser.parseExpression(expression)

        .getValue(societyContext, String.class);

// queryResultString = "Nikola Tesla is a member of the IEEE Society"

 

Also see the next section on the Elvis operator for an even shorter syntax for the ternary operator.

参照下一节可以使用Elvis操作符实现更加简短的三元操作符语法。

 

10.5.15 The Elvis Operator

Elvis操作符

 

The Elvis operator is a shortening of the ternary operator syntax and is used in the Groovy language. With the ternary operator syntax you usually have to repeat a variable twice, for example:

Elvis操作符是在Groovy语言中使用的比较简短的三元操作符。使用三元操作符你可以重复一个变量两次,如下:

 

String name = "Elvis Presley";

String displayName = name != null ? name : "Unknown";

 

Instead you can use the Elvis operator, named for the resemblance to Elvis' hair style.

你可以使用Elvis操作符来实现,上面例子的也可以如下的形式展现。

 

ExpressionParser parser = new SpelExpressionParser();

 

String name = parser.parseExpression("name?:'Unknown'").getValue(String.class);

 

System.out.println(name); // 'Unknown'

 

Here is a more complex example.

下面是一个比较复杂的例子。

 

ExpressionParser parser = new SpelExpressionParser();

 

Inventor tesla = new Inventor("Nikola Tesla", "Serbian");

StandardEvaluationContext context = new StandardEvaluationContext(tesla);

 

String name = parser.parseExpression("Name?:'Elvis Presley'").getValue(context, String.class);

 

System.out.println(name); // Nikola Tesla

 

tesla.setName(null);

 

name = parser.parseExpression("Name?:'Elvis Presley'").getValue(context, String.class);

 

System.out.println(name); // Elvis Presley

 

10.5.16 Safe Navigation operator

安全的导航操作符

 

The Safe Navigation operator is used to avoid a NullPointerException and comes from the Groovy language. Typically when you have a reference to an object you might need to verify that it is not null before accessing methods or properties of the object. To avoid this, the safe navigation operator will simply return null instead of throwing an exception.

安全的导航操作符用于避免空指针异常并且来自Groovy语言。通常当你指向一个object你希望判断是否为空在访问方法或属性之前。为了避免如此,安全的导航操作符将简单返回null而不是抛出一个异常。

 

ExpressionParser parser = new SpelExpressionParser();

 

Inventor tesla = new Inventor("Nikola Tesla", "Serbian");

tesla.setPlaceOfBirth(new PlaceOfBirth("Smiljan"));

 

StandardEvaluationContext context = new StandardEvaluationContext(tesla);

 

String city = parser.parseExpression("PlaceOfBirth?.City").getValue(context, String.class);

System.out.println(city); // Smiljan

 

tesla.setPlaceOfBirth(null);

 

city = parser.parseExpression("PlaceOfBirth?.City").getValue(context, String.class);

 

System.out.println(city); // null - does not throw NullPointerException!!!

 

[Note]

注意

 

The Elvis operator can be used to apply default values in expressions, e.g. in an @Value expression:

Elvis操作符可以在表达式中应用于默认值,例如,在@Value表达式中:

 

@Value("#{systemProperties['pop3.port'] ?: 25}")

 

This will inject a system property pop3.port if it is defined or 25 if not.

这样会调用系统参数pop3.port,如果没有定义将会返回25。

 

10.5.17 Collection Selection

集合的选择

 

Selection is a powerful expression language feature that allows you to transform some source collection into another by selecting from its entries.

选择是一个强大的表达式语言特性允许你将一些源数据集合转换为另一个集合通过选择他们的条目。

 

Selection uses the syntax ?[selectionExpression]. This will filter the collection and return a new collection containing a subset of the original elements. For example, selection would allow us to easily get a list of Serbian inventors:

选择使用语法是?[selectionExpression]。这将会过滤集合并返回一个新的集合包含一个原始数据的子集合。例如,选择应当允许我们简单获得一个Serbian inventors的list:

 

List<Inventor> list = (List<Inventor>) parser.parseExpression(

        "Members.?[Nationality == 'Serbian']").getValue(societyContext);

 

Selection is possible upon both lists and maps. In the former case the selection criteria is evaluated against each individual list element whilst against a map the selection criteria is evaluated against each map entry (objects of the Java type Map.Entry). Map entries have their key and value accessible as properties for use in the selection.

选择可以使用在list和map上。在前面的例子中选择独立处理了集合中的元素,而当选择一个map时将会处理每个map的entry(Java类型Map.Entry的object)。Map的entry有他的key和value作为属性访问使用在选择中。

 

This expression will return a new map consisting of those elements of the original map where the entry value is less than 27.

表达式将返回一个新的map包括原有map中所有的value小于27的条目。

 

Map newMap = parser.parseExpression("map.?[value<27]").getValue();

 

In addition to returning all the selected elements, it is possible to retrieve just the first or the last value. To obtain the first entry matching the selection the syntax is ^[…?] whilst to obtain the last matching selection the syntax is $[…?].

额外为了返回所有选择的元素,可以获得第一个值或最后一个值。为了获得第一个条目在选择的语法是^[…?]而获得最后一个值的语法是$[…?]。

 

10.5.18 Collection Projection

集合投影

 

Projection allows a collection to drive the evaluation of a sub-expression and the result is a new collection. The syntax for projection is ![projectionExpression]. Most easily understood by example, suppose we have a list of inventors but want the list of cities where they were born. Effectively we want to evaluate 'placeOfBirth.city' for every entry in the inventor list. Using projection:

投影允许一个集合被一个子表达式处理而且结果是一个新的集合。投影的语法是![projectionExpression]。通过例子可便于理解,假设我们有一个invertors的list并且希望他们出生的cities的list。有效的做法是我们希望对每个在invertor的list调用'placeOfBirth.city'。使用投影:

 

// returns ['Smiljan', 'Idvor' ]

List placesOfBirth = (List)parser.parseExpression("Members.![placeOfBirth.city]");

 

A map can also be used to drive projection and in this case the projection expression is evaluated against each entry in the map (represented as a Java Map.Entry). The result of a projection across a map is a list consisting of the evaluation of the projection expression against each map entry.

一个map可以用于处理投影并且在这种情况下投影表达式可以对map中的每个entry进行处理(作为一个Java的Map.Entry)。投影的结果跨越map是一个list包含对每一个map条目处理的投影表达式。

 

10.5.19 Expression templating

表达式模板

 

Expression templates allow a mixing of literal text with one or more evaluation blocks. Each evaluation block is delimited with prefix and suffix characters that you can define, a common choice is to use #{ } as the delimiters. For example,

表达式模板允许一个混合的文本有一个或多个评价块。每个评价块用前缀和后缀区分你可以定义一个通用的选项通过使用#{}作为一个分隔符。例如,

 

String randomPhrase = parser.parseExpression(

        "random number is #{T(java.lang.Math).random()}",

        new TemplateParserContext()).getValue(String.class);

 

// evaluates to "random number is 0.7038186818312008"

 

The string is evaluated by concatenating the literal text 'random number is ' with the result of evaluating the expression inside the #{ } delimiter, in this case the result of calling that random() method. The second argument to the method parseExpression() is of the type ParserContext. The ParserContext interface is used to influence how the expression is parsed in order to support the expression templating functionality. The definition of TemplateParserContext is shown below.

字符串包含一个文本'random number is '和在#{}中的表达式的处理结果,在这个例子中结果调用了random方法。第二个参数对于parseExpression方法是ParseContext的类型。ParserContext接口被使用来影响表达式是如何被解析来支持表达式的模板。定义TemplateParserContext的方法如下。

 

public class TemplateParserContext implements ParserContext {

 

    public String getExpressionPrefix() {

        return "#{";

    }

 

    public String getExpressionSuffix() {

        return "}";

    }

 

    public boolean isTemplate() {

        return true;

    }

}

 

10.6 Classes used in the examples

 

Inventor.java

 

package org.spring.samples.spel.inventor;

 

import java.util.Date;

import java.util.GregorianCalendar;

 

public class Inventor {

 

    private String name;

    private String nationality;

    private String[] inventions;

    private Date birthdate;

    private PlaceOfBirth placeOfBirth;

 

    public Inventor(String name, String nationality) {

        GregorianCalendar c= new GregorianCalendar();

        this.name = name;

        this.nationality = nationality;

        this.birthdate = c.getTime();

    }

 

    public Inventor(String name, Date birthdate, String nationality) {

        this.name = name;

        this.nationality = nationality;

        this.birthdate = birthdate;

    }

 

    public Inventor() {

    }

 

    public String getName() {

        return name;

    }

 

    public void setName(String name) {

        this.name = name;

    }

 

    public String getNationality() {

        return nationality;

    }

 

    public void setNationality(String nationality) {

        this.nationality = nationality;

    }

 

    public Date getBirthdate() {

        return birthdate;

    }

 

    public void setBirthdate(Date birthdate) {

        this.birthdate = birthdate;

    }

 

    public PlaceOfBirth getPlaceOfBirth() {

        return placeOfBirth;

    }

 

    public void setPlaceOfBirth(PlaceOfBirth placeOfBirth) {

        this.placeOfBirth = placeOfBirth;

    }

 

    public void setInventions(String[] inventions) {

        this.inventions = inventions;

    }

 

    public String[] getInventions() {

        return inventions;

    }

}

 

PlaceOfBirth.java

 

package org.spring.samples.spel.inventor;

 

public class PlaceOfBirth {

 

    private String city;

    private String country;

 

    public PlaceOfBirth(String city) {

        this.city=city;

    }

 

    public PlaceOfBirth(String city, String country) {

        this(city);

        this.country = country;

    }

 

    public String getCity() {

        return city;

    }

 

    public void setCity(String s) {

        this.city = s;

    }

 

    public String getCountry() {

        return country;

    }

 

    public void setCountry(String country) {

        this.country = country;

    }

 

}

 

Society.java

 

package org.spring.samples.spel.inventor;

 

import java.util.*;

 

public class Society {

 

    private String name;

 

    public static String Advisors = "advisors";

    public static String President = "president";

 

    private List<Inventor> members = new ArrayList<Inventor>();

    private Map officers = new HashMap();

 

    public List getMembers() {

        return members;

    }

 

    public Map getOfficers() {

        return officers;

    }

 

    public String getName() {

        return name;

    }

 

    public void setName(String name) {

        this.name = name;

    }

 

    public boolean isMember(String name) {

        for (Inventor inventor : members) {

            if (inventor.getName().equals(name)) {

                return true;

            }

        }

        return false;

    }

 

}

 

 


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表