Skip to content

Commit

Permalink
spring-projectsGH-34: Resolve Placeholders in Expressions
Browse files Browse the repository at this point in the history
Further enhancement to spring-projects#34
  • Loading branch information
garyrussell committed Dec 1, 2016
1 parent ba35d97 commit 902c45c
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 10 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,8 @@ public void service3() {

These use the familier Spring SpEL expression syntax (`#{...}`).

Expressions can contain property placeholders such as `#{${max.delay}}` or `#{@exceptionChecker.${retry.method}(#root)}`

- `exceptionExpression` is evaluated against the thrown exception as the `#root` object.
- `maxAttemptsExpression` and the `@BackOff` expression attributes are evaluated once, during initialization; there is no root object for the evaluation but they can reference other beans in the context.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.annotation.AnnotationUtils;
Expand Down Expand Up @@ -288,11 +289,11 @@ private RetryPolicy getRetryPolicy(Annotation retryable) {
Integer maxAttempts = (Integer) attrs.get("maxAttempts");
String maxAttemptsExpression = (String) attrs.get("maxAttemptsExpression");
if (StringUtils.hasText(maxAttemptsExpression)) {
maxAttempts = PARSER.parseExpression(maxAttemptsExpression, PARSER_CONTEXT).getValue(this.evaluationContext,
Integer.class);
maxAttempts = PARSER.parseExpression(resolve(maxAttemptsExpression), PARSER_CONTEXT)
.getValue(this.evaluationContext, Integer.class);
}
if (includes.length == 0 && excludes.length == 0) {
SimpleRetryPolicy simple = hasExpression ? new ExpressionRetryPolicy(exceptionExpression)
SimpleRetryPolicy simple = hasExpression ? new ExpressionRetryPolicy(resolve(exceptionExpression))
.withBeanFactory(this.beanFactory)
: new SimpleRetryPolicy();
simple.setMaxAttempts(maxAttempts);
Expand All @@ -317,17 +318,17 @@ private RetryPolicy getRetryPolicy(Annotation retryable) {
private BackOffPolicy getBackoffPolicy(Backoff backoff) {
long min = backoff.delay() == 0 ? backoff.value() : backoff.delay();
if (StringUtils.hasText(backoff.delayExpression())) {
min = PARSER.parseExpression(backoff.delayExpression(), PARSER_CONTEXT).getValue(this.evaluationContext,
Long.class);
min = PARSER.parseExpression(resolve(backoff.delayExpression()), PARSER_CONTEXT)
.getValue(this.evaluationContext, Long.class);
}
long max = backoff.maxDelay();
if (StringUtils.hasText(backoff.maxDelayExpression())) {
max = PARSER.parseExpression(backoff.maxDelayExpression(), PARSER_CONTEXT).getValue(this.evaluationContext,
Long.class);
max = PARSER.parseExpression(resolve(backoff.maxDelayExpression()), PARSER_CONTEXT)
.getValue(this.evaluationContext, Long.class);
}
double multiplier = backoff.multiplier();
if (StringUtils.hasText(backoff.multiplierExpression())) {
multiplier = PARSER.parseExpression(backoff.multiplierExpression(), PARSER_CONTEXT)
multiplier = PARSER.parseExpression(resolve(backoff.multiplierExpression()), PARSER_CONTEXT)
.getValue(this.evaluationContext, Double.class);
}
if (multiplier > 0) {
Expand Down Expand Up @@ -360,4 +361,16 @@ private BackOffPolicy getBackoffPolicy(Backoff backoff) {
return policy;
}

/**
* Resolve the specified value if possible.
*
* @see ConfigurableBeanFactory#resolveEmbeddedValue
*/
private String resolve(String value) {
if (this.beanFactory != null && this.beanFactory instanceof ConfigurableBeanFactory) {
return ((ConfigurableBeanFactory) this.beanFactory).resolveEmbeddedValue(value);
}
return value;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

import java.lang.reflect.Method;
import java.util.Map;
import java.util.Properties;

import org.aopalliance.intercept.MethodInterceptor;
import org.junit.Test;
Expand All @@ -33,6 +34,7 @@
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
import org.springframework.retry.backoff.Sleeper;
import org.springframework.retry.interceptor.RetryInterceptorBuilder;
Expand Down Expand Up @@ -215,6 +217,18 @@ public Service service() {
@EnableRetry
protected static class TestConfiguration {

@Bean
public static PropertySourcesPlaceholderConfigurer pspc() {
PropertySourcesPlaceholderConfigurer pspc = new PropertySourcesPlaceholderConfigurer();
Properties properties = new Properties();
properties.setProperty("one", "1");
properties.setProperty("five", "5");
properties.setProperty("onePointOne", "1.1");
properties.setProperty("retryMethod", "shouldRetry");
pspc.setProperties(properties);
return pspc;
}

@SuppressWarnings("serial")
@Bean
public Sleeper sleeper() {
Expand Down Expand Up @@ -447,9 +461,10 @@ public void service2() {
throw new RuntimeException("this cannot be retried");
}

@Retryable(exceptionExpression="#{@exceptionChecker.shouldRetry(#root)}",
@Retryable(exceptionExpression="#{@exceptionChecker.${retryMethod}(#root)}",
maxAttemptsExpression = "#{@integerFiveBean}",
backoff = @Backoff(delayExpression = "#{1}", maxDelayExpression = "#{5}", multiplierExpression = "#{1.1}"))
backoff = @Backoff(delayExpression = "#{${one}}", maxDelayExpression = "#{${five}}",
multiplierExpression = "#{${onePointOne}}"))
public void service3() {
if (count++ < 8) {
throw new RuntimeException();
Expand Down

0 comments on commit 902c45c

Please sign in to comment.