SpelMessageInterpolator.java

package cn.home1.oss.lib.common.msginterpolate;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.expression.MapAccessor;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionException;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.util.Assert;

import java.util.Map;

/**
 * Implementation of the {@link MessageInterpolator} that uses the Spring Expression Language (SpEL)
 * to evaluate expressions inside a template message.
 *
 * <p>
 * SpEL expressions are delimited by {@code #{} and {@code }}. The provided variables are accessible
 * directly by name.
 * </p>
 */
public class SpelMessageInterpolator implements MessageInterpolator {

  private static final Logger log = LoggerFactory.getLogger(SpelMessageInterpolator.class);

  private final EvaluationContext evalContext;

  /**
   * Creates a new instance with a custom {@link EvaluationContext}.
   *
   * @param evalContext evalContext
   */
  public SpelMessageInterpolator(final EvaluationContext evalContext) {
    Assert.notNull(evalContext, "EvaluationContext must not be null");
    this.evalContext = evalContext;
  }

  /**
   * Creates a new instance with {@link StandardEvaluationContext} including
   * {@link org.springframework.expression.spel.support.ReflectivePropertyAccessor
   * ReflectivePropertyAccessor} and {@link MapAccessor}.
   */
  public SpelMessageInterpolator() {
    final StandardEvaluationContext ctx = new StandardEvaluationContext();
    ctx.addPropertyAccessor(new MapAccessor());
    this.evalContext = ctx;
  }

  @Override
  public String interpolate(final String template, final Map<String, Object> variables) {
    Assert.notNull(template, "messageTemplate must not be null");

    String result;
    try {
      final Expression expression = parser().parseExpression(template, new TemplateParserContext());
      result = expression.getValue(this.evalContext, variables, String.class);
    } catch (final ExpressionException ex) {
      result = "Failed to interpolate message template, error: " + ex.getMessage(); // TODO test this
      log.warn("Failed to interpolate message template: {}, variables: {}", template, variables, ex);
    }
    return result;
  }

  ExpressionParser parser() {
    return new SpelExpressionParser();
  }
}