View Javadoc
1   package cn.home1.oss.lib.common.msginterpolate;
2   
3   import org.slf4j.Logger;
4   import org.slf4j.LoggerFactory;
5   import org.springframework.context.expression.MapAccessor;
6   import org.springframework.expression.EvaluationContext;
7   import org.springframework.expression.Expression;
8   import org.springframework.expression.ExpressionException;
9   import org.springframework.expression.ExpressionParser;
10  import org.springframework.expression.common.TemplateParserContext;
11  import org.springframework.expression.spel.standard.SpelExpressionParser;
12  import org.springframework.expression.spel.support.StandardEvaluationContext;
13  import org.springframework.util.Assert;
14  
15  import java.util.Map;
16  
17  /**
18   * Implementation of the {@link MessageInterpolator} that uses the Spring Expression Language (SpEL)
19   * to evaluate expressions inside a template message.
20   *
21   * <p>
22   * SpEL expressions are delimited by {@code #{} and {@code }}. The provided variables are accessible
23   * directly by name.
24   * </p>
25   */
26  public class SpelMessageInterpolator implements MessageInterpolator {
27  
28    private static final Logger log = LoggerFactory.getLogger(SpelMessageInterpolator.class);
29  
30    private final EvaluationContext evalContext;
31  
32    /**
33     * Creates a new instance with a custom {@link EvaluationContext}.
34     *
35     * @param evalContext evalContext
36     */
37    public SpelMessageInterpolator(final EvaluationContext evalContext) {
38      Assert.notNull(evalContext, "EvaluationContext must not be null");
39      this.evalContext = evalContext;
40    }
41  
42    /**
43     * Creates a new instance with {@link StandardEvaluationContext} including
44     * {@link org.springframework.expression.spel.support.ReflectivePropertyAccessor
45     * ReflectivePropertyAccessor} and {@link MapAccessor}.
46     */
47    public SpelMessageInterpolator() {
48      final StandardEvaluationContext ctx = new StandardEvaluationContext();
49      ctx.addPropertyAccessor(new MapAccessor());
50      this.evalContext = ctx;
51    }
52  
53    @Override
54    public String interpolate(final String template, final Map<String, Object> variables) {
55      Assert.notNull(template, "messageTemplate must not be null");
56  
57      String result;
58      try {
59        final Expression expression = parser().parseExpression(template, new TemplateParserContext());
60        result = expression.getValue(this.evalContext, variables, String.class);
61      } catch (final ExpressionException ex) {
62        result = "Failed to interpolate message template, error: " + ex.getMessage(); // TODO test this
63        log.warn("Failed to interpolate message template: {}, variables: {}", template, variables, ex);
64      }
65      return result;
66    }
67  
68    ExpressionParser parser() {
69      return new SpelExpressionParser();
70    }
71  }