SpEL est Le langage d’expression spécifique à Spring Framework.
Il est utilisé à plusieurs endroits, comme dans l’annotation @Value
ou avec les annotations de Spring Security
Exemples
Dans ce premier exemple, on récupère la clé d’API du service mail.
Il a été enregistré sous forme de propriété dans le fichier application.yml
.
@Configuration
public class EmailConfig {
@Value("${application.email.api-key}")
private String apiKey;
...
}
Dans ce deuxième exemple, on réstreint l’accès à une méthode aux utilisateurs qui ont le rôle d’administrateur.
@Service
public class ProductService {
@PreAuthorize("hasRole('ROLE_ADMIN')")
private void create(Product product) {
...
}
...
}
Syntaxe
Pour la syntaxe complète, il faut aller voir la documentation de référence du langage. Une bonne partie de la syntaxe ressemble à Java, avec quelques spécificités.
-
Expression simple
-
Classe:
T(java.lang.Math)
-
Paramètres (ou variable):
#product
, avec 2 variables spécifiques: #this et #root -
Beans:
@productService
s’il y a un bean resolver, et&productService
pour s’adresser directement au beanFactory, comme pour les propriétés -
Propriétés:
${application.email.api-key}
-
Expressions mixtes, c’est à dire une expression dans du texte statique:
"random number is #{T(java.lang.Math).random()}"
-
Fonctions et méthodes
Résolution d’expression
On se préoccupe rarement de l’API de résolution puisque l’usage le plus courant est dans les annotations. Dans certains cas, on peut avoir besoin de le faire par programmation.
Expression simple
String exp = "0.1 + T(java.lang.Math).random()";
ExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression(exp);
Double value = expression.getValue(Double.class);
Expression avec paramètre
String exp = "new java.util.Random().nextInt(#bound)";
ExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression(exp);
StandardEvaluationContext context = new StandardEvaluationContext();
context.setVariable("bound", 100);
Integer value = expression.getValue(context, Integer.class);
Expression avec beans
Si l’expression fait référence à des beans, ceux-ci doivent être résolus.
String exp = "@randomService.nextInt(#bound)";
ExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression(exp);
StandardEvaluationContext context = new StandardEvaluationContext();
context.setVariable("bound", 100);
context.setBeanResolver(new BeanFactoryResolver(beanFactory));
Integer value = expression.getValue(context, Integer.class);
Expression de sécurité
Les annotations de sécurité comme @PreAuthorize ou @PostFilter utilisent des méthodes comme isAuthenticated()
, isAnonymous()
ou hasRole(…)
.
Ces méthodes sont dans la classe SecurityExpressionRoot
qu’il faut donc utiliser comme racine du parser.
String exp = "hasRole('ROLE_ADMIN')";
ExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression(exp);
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
SecurityExpressionRoot securityRoot = new SecurityExpressionRoot(authentication) {};
Boolean value = expression.getValue(securityRoot, Boolean.class);
Pour les exemples complets, on peut passer un contexte et une racine.
Boolean value = expression.getValue(context, securityRoot, Boolean.class);
Références