Revise and document TimeUnit support in @Scheduled

This commit also fixes a bug introduced in commit e99b43b91e, where
java.time.Duration strings were converted to milliseconds and then
converted again using the configured TimeUnit.

See gh-27309
This commit is contained in:
Sam Brannen
2021-08-25 20:46:51 +02:00
parent e99b43b91e
commit bd72e4498b
4 changed files with 249 additions and 321 deletions

View File

@@ -33,6 +33,12 @@ import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ParameterContext;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.converter.ArgumentConversionException;
import org.junit.jupiter.params.converter.ArgumentConverter;
import org.junit.jupiter.params.converter.ConvertWith;
import org.junit.jupiter.params.provider.CsvSource;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.scope.ScopedProxyUtils;
@@ -61,8 +67,11 @@ import org.springframework.validation.beanvalidation.MethodValidationPostProcess
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.SoftAssertions.assertSoftly;
/**
* Tests for {@link ScheduledAnnotationBeanPostProcessor}.
*
* @author Mark Fisher
* @author Juergen Hoeller
* @author Chris Beams
@@ -70,21 +79,25 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
* @author Stevo Slavić
* @author Victor Brown
*/
public class ScheduledAnnotationBeanPostProcessorTests {
class ScheduledAnnotationBeanPostProcessorTests {
private final StaticApplicationContext context = new StaticApplicationContext();
@AfterEach
public void closeContextAfterTest() {
void closeContextAfterTest() {
context.close();
}
@Test
public void fixedDelayTask() {
@ParameterizedTest
@CsvSource({
"FixedDelay, 5000",
"FixedDelayInSeconds, 5000",
"FixedDelayInMinutes, 180000"
})
void fixedDelayTask(@NameToClass Class<?> beanClass, long expectedInterval) {
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
BeanDefinition targetDefinition = new RootBeanDefinition(FixedDelayTestBean.class);
BeanDefinition targetDefinition = new RootBeanDefinition(beanClass);
context.registerBeanDefinition("postProcessor", processorDefinition);
context.registerBeanDefinition("target", targetDefinition);
context.refresh();
@@ -98,7 +111,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
@SuppressWarnings("unchecked")
List<IntervalTask> fixedDelayTasks = (List<IntervalTask>)
new DirectFieldAccessor(registrar).getPropertyValue("fixedDelayTasks");
assertThat(fixedDelayTasks.size()).isEqualTo(1);
assertThat(fixedDelayTasks).hasSize(1);
IntervalTask task = fixedDelayTasks.get(0);
ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task.getRunnable();
Object targetObject = runnable.getTarget();
@@ -106,69 +119,18 @@ public class ScheduledAnnotationBeanPostProcessorTests {
assertThat(targetObject).isEqualTo(target);
assertThat(targetMethod.getName()).isEqualTo("fixedDelay");
assertThat(task.getInitialDelay()).isEqualTo(0L);
assertThat(task.getInterval()).isEqualTo(5000L);
assertThat(task.getInterval()).isEqualTo(expectedInterval);
}
@Test
public void fixedDelayWithSecondsTimeUnitTask() {
@ParameterizedTest
@CsvSource({
"FixedRate, 3000",
"FixedRateInSeconds, 5000",
"FixedRateInMinutes, 180000"
})
void fixedRateTask(@NameToClass Class<?> beanClass, long expectedInterval) {
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
BeanDefinition targetDefinition = new RootBeanDefinition(FixedDelayWithSecondsTimeUnitTestBean.class);
context.registerBeanDefinition("postProcessor", processorDefinition);
context.registerBeanDefinition("target", targetDefinition);
context.refresh();
ScheduledTaskHolder postProcessor = context.getBean("postProcessor", ScheduledTaskHolder.class);
assertThat(postProcessor.getScheduledTasks().size()).isEqualTo(1);
Object target = context.getBean("target");
ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar)
new DirectFieldAccessor(postProcessor).getPropertyValue("registrar");
@SuppressWarnings("unchecked")
List<IntervalTask> fixedDelayTasks = (List<IntervalTask>)
new DirectFieldAccessor(registrar).getPropertyValue("fixedDelayTasks");
assertThat(fixedDelayTasks.size()).isEqualTo(1);
IntervalTask task = fixedDelayTasks.get(0);
ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task.getRunnable();
Object targetObject = runnable.getTarget();
Method targetMethod = runnable.getMethod();
assertThat(targetObject).isEqualTo(target);
assertThat(targetMethod.getName()).isEqualTo("fixedDelay");
assertThat(task.getInitialDelay()).isEqualTo(0L);
assertThat(task.getInterval()).isEqualTo(5000L);
}
@Test
public void fixedDelayWithMinutesTimeUnitTask() {
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
BeanDefinition targetDefinition = new RootBeanDefinition(FixedDelayWithMinutesTimeUnitTestBean.class);
context.registerBeanDefinition("postProcessor", processorDefinition);
context.registerBeanDefinition("target", targetDefinition);
context.refresh();
ScheduledTaskHolder postProcessor = context.getBean("postProcessor", ScheduledTaskHolder.class);
assertThat(postProcessor.getScheduledTasks().size()).isEqualTo(1);
Object target = context.getBean("target");
ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar)
new DirectFieldAccessor(postProcessor).getPropertyValue("registrar");
@SuppressWarnings("unchecked")
List<IntervalTask> fixedDelayTasks = (List<IntervalTask>)
new DirectFieldAccessor(registrar).getPropertyValue("fixedDelayTasks");
assertThat(fixedDelayTasks.size()).isEqualTo(1);
IntervalTask task = fixedDelayTasks.get(0);
ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task.getRunnable();
Object targetObject = runnable.getTarget();
Method targetMethod = runnable.getMethod();
assertThat(targetObject).isEqualTo(target);
assertThat(targetMethod.getName()).isEqualTo("fixedDelay");
assertThat(task.getInitialDelay()).isEqualTo(0L);
assertThat(task.getInterval()).isEqualTo(180000L);
}
@Test
public void fixedRateTask() {
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
BeanDefinition targetDefinition = new RootBeanDefinition(FixedRateTestBean.class);
BeanDefinition targetDefinition = new RootBeanDefinition(beanClass);
context.registerBeanDefinition("postProcessor", processorDefinition);
context.registerBeanDefinition("target", targetDefinition);
context.refresh();
@@ -189,14 +151,21 @@ public class ScheduledAnnotationBeanPostProcessorTests {
Method targetMethod = runnable.getMethod();
assertThat(targetObject).isEqualTo(target);
assertThat(targetMethod.getName()).isEqualTo("fixedRate");
assertThat(task.getInitialDelay()).isEqualTo(0L);
assertThat(task.getInterval()).isEqualTo(3000L);
assertSoftly(softly -> {
softly.assertThat(task.getInitialDelay()).as("initial delay").isEqualTo(0);
softly.assertThat(task.getInterval()).as("interval").isEqualTo(expectedInterval);
});
}
@Test
public void fixedRateWithSecondsTimeUnitTask() {
@ParameterizedTest
@CsvSource({
"FixedRateWithInitialDelay, 1000, 3000",
"FixedRateWithInitialDelayInSeconds, 5000, 3000",
"FixedRateWithInitialDelayInMinutes, 60000, 180000"
})
void fixedRateTaskWithInitialDelay(@NameToClass Class<?> beanClass, long expectedInitialDelay, long expectedInterval) {
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
BeanDefinition targetDefinition = new RootBeanDefinition(FixedRateWithSecondsTimeUnitTestBean.class);
BeanDefinition targetDefinition = new RootBeanDefinition(beanClass);
context.registerBeanDefinition("postProcessor", processorDefinition);
context.registerBeanDefinition("target", targetDefinition);
context.refresh();
@@ -217,152 +186,42 @@ public class ScheduledAnnotationBeanPostProcessorTests {
Method targetMethod = runnable.getMethod();
assertThat(targetObject).isEqualTo(target);
assertThat(targetMethod.getName()).isEqualTo("fixedRate");
assertThat(task.getInitialDelay()).isEqualTo(0L);
assertThat(task.getInterval()).isEqualTo(5000L);
assertSoftly(softly -> {
softly.assertThat(task.getInitialDelay()).as("initial delay").isEqualTo(expectedInitialDelay);
softly.assertThat(task.getInterval()).as("interval").isEqualTo(expectedInterval);
});
}
@Test
public void fixedRateWithMinutesTimeUnitTask() {
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
BeanDefinition targetDefinition = new RootBeanDefinition(FixedRateWithMinutesTimeUnitTestBean.class);
context.registerBeanDefinition("postProcessor", processorDefinition);
context.registerBeanDefinition("target", targetDefinition);
context.refresh();
ScheduledTaskHolder postProcessor = context.getBean("postProcessor", ScheduledTaskHolder.class);
assertThat(postProcessor.getScheduledTasks().size()).isEqualTo(1);
Object target = context.getBean("target");
ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar)
new DirectFieldAccessor(postProcessor).getPropertyValue("registrar");
@SuppressWarnings("unchecked")
List<IntervalTask> fixedRateTasks = (List<IntervalTask>)
new DirectFieldAccessor(registrar).getPropertyValue("fixedRateTasks");
assertThat(fixedRateTasks.size()).isEqualTo(1);
IntervalTask task = fixedRateTasks.get(0);
ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task.getRunnable();
Object targetObject = runnable.getTarget();
Method targetMethod = runnable.getMethod();
assertThat(targetObject).isEqualTo(target);
assertThat(targetMethod.getName()).isEqualTo("fixedRate");
assertThat(task.getInitialDelay()).isEqualTo(0L);
assertThat(task.getInterval()).isEqualTo(180000L);
}
@Test
public void fixedRateTaskWithInitialDelay() {
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
BeanDefinition targetDefinition = new RootBeanDefinition(FixedRateWithInitialDelayTestBean.class);
context.registerBeanDefinition("postProcessor", processorDefinition);
context.registerBeanDefinition("target", targetDefinition);
context.refresh();
ScheduledTaskHolder postProcessor = context.getBean("postProcessor", ScheduledTaskHolder.class);
assertThat(postProcessor.getScheduledTasks().size()).isEqualTo(1);
Object target = context.getBean("target");
ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar)
new DirectFieldAccessor(postProcessor).getPropertyValue("registrar");
@SuppressWarnings("unchecked")
List<IntervalTask> fixedRateTasks = (List<IntervalTask>)
new DirectFieldAccessor(registrar).getPropertyValue("fixedRateTasks");
assertThat(fixedRateTasks.size()).isEqualTo(1);
IntervalTask task = fixedRateTasks.get(0);
ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task.getRunnable();
Object targetObject = runnable.getTarget();
Method targetMethod = runnable.getMethod();
assertThat(targetObject).isEqualTo(target);
assertThat(targetMethod.getName()).isEqualTo("fixedRate");
assertThat(task.getInitialDelay()).isEqualTo(1000L);
assertThat(task.getInterval()).isEqualTo(3000L);
}
@Test
public void fixedRateTaskWithSecondsTimeUnitWithInitialDelay() {
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
BeanDefinition targetDefinition = new RootBeanDefinition(FixedRateWithSecondsTimeUnitInitialDelayTestBean.class);
context.registerBeanDefinition("postProcessor", processorDefinition);
context.registerBeanDefinition("target", targetDefinition);
context.refresh();
ScheduledTaskHolder postProcessor = context.getBean("postProcessor", ScheduledTaskHolder.class);
assertThat(postProcessor.getScheduledTasks().size()).isEqualTo(1);
Object target = context.getBean("target");
ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar)
new DirectFieldAccessor(postProcessor).getPropertyValue("registrar");
@SuppressWarnings("unchecked")
List<IntervalTask> fixedRateTasks = (List<IntervalTask>)
new DirectFieldAccessor(registrar).getPropertyValue("fixedRateTasks");
assertThat(fixedRateTasks.size()).isEqualTo(1);
IntervalTask task = fixedRateTasks.get(0);
ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task.getRunnable();
Object targetObject = runnable.getTarget();
Method targetMethod = runnable.getMethod();
assertThat(targetObject).isEqualTo(target);
assertThat(targetMethod.getName()).isEqualTo("fixedRate");
assertThat(task.getInitialDelay()).isEqualTo(5000L);
assertThat(task.getInterval()).isEqualTo(3000L);
}
@Test
public void fixedRateTaskWithMinutesTimeUnitWithInitialDelay() {
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
BeanDefinition targetDefinition = new RootBeanDefinition(FixedRateWithMinutesTimeUnitInitialDelayTestBean.class);
context.registerBeanDefinition("postProcessor", processorDefinition);
context.registerBeanDefinition("target", targetDefinition);
context.refresh();
ScheduledTaskHolder postProcessor = context.getBean("postProcessor", ScheduledTaskHolder.class);
assertThat(postProcessor.getScheduledTasks().size()).isEqualTo(1);
Object target = context.getBean("target");
ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar)
new DirectFieldAccessor(postProcessor).getPropertyValue("registrar");
@SuppressWarnings("unchecked")
List<IntervalTask> fixedRateTasks = (List<IntervalTask>)
new DirectFieldAccessor(registrar).getPropertyValue("fixedRateTasks");
assertThat(fixedRateTasks.size()).isEqualTo(1);
IntervalTask task = fixedRateTasks.get(0);
ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task.getRunnable();
Object targetObject = runnable.getTarget();
Method targetMethod = runnable.getMethod();
assertThat(targetObject).isEqualTo(target);
assertThat(targetMethod.getName()).isEqualTo("fixedRate");
assertThat(task.getInitialDelay()).isEqualTo(60000L);
assertThat(task.getInterval()).isEqualTo(180000L);
}
@Test
public void severalFixedRatesWithRepeatedScheduledAnnotation() {
void severalFixedRatesWithRepeatedScheduledAnnotation() {
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
BeanDefinition targetDefinition = new RootBeanDefinition(SeveralFixedRatesWithRepeatedScheduledAnnotationTestBean.class);
severalFixedRates(context, processorDefinition, targetDefinition);
}
@Test
public void severalFixedRatesWithSchedulesContainerAnnotation() {
void severalFixedRatesWithSchedulesContainerAnnotation() {
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
BeanDefinition targetDefinition = new RootBeanDefinition(SeveralFixedRatesWithSchedulesContainerAnnotationTestBean.class);
severalFixedRates(context, processorDefinition, targetDefinition);
}
@Test
public void severalFixedRatesOnBaseClass() {
void severalFixedRatesOnBaseClass() {
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
BeanDefinition targetDefinition = new RootBeanDefinition(FixedRatesSubBean.class);
severalFixedRates(context, processorDefinition, targetDefinition);
}
@Test
public void severalFixedRatesOnDefaultMethod() {
void severalFixedRatesOnDefaultMethod() {
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
BeanDefinition targetDefinition = new RootBeanDefinition(FixedRatesDefaultBean.class);
severalFixedRates(context, processorDefinition, targetDefinition);
}
@Test
public void severalFixedRatesAgainstNestedCglibProxy() {
void severalFixedRatesAgainstNestedCglibProxy() {
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
BeanDefinition targetDefinition = new RootBeanDefinition(SeveralFixedRatesWithRepeatedScheduledAnnotationTestBean.class);
targetDefinition.setFactoryMethodName("nestedProxy");
@@ -405,7 +264,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
@Test
public void cronTask() {
void cronTask() {
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
BeanDefinition targetDefinition = new RootBeanDefinition(CronTestBean.class);
context.registerBeanDefinition("postProcessor", processorDefinition);
@@ -432,7 +291,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
@Test
public void cronTaskWithZone() {
void cronTaskWithZone() {
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
BeanDefinition targetDefinition = new RootBeanDefinition(CronWithTimezoneTestBean.class);
context.registerBeanDefinition("postProcessor", processorDefinition);
@@ -478,7 +337,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
@Test
public void cronTaskWithInvalidZone() {
void cronTaskWithInvalidZone() {
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
BeanDefinition targetDefinition = new RootBeanDefinition(CronWithInvalidTimezoneTestBean.class);
context.registerBeanDefinition("postProcessor", processorDefinition);
@@ -488,7 +347,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
@Test
public void cronTaskWithMethodValidation() {
void cronTaskWithMethodValidation() {
BeanDefinition validationDefinition = new RootBeanDefinition(MethodValidationPostProcessor.class);
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
BeanDefinition targetDefinition = new RootBeanDefinition(CronTestBean.class);
@@ -500,7 +359,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
@Test
public void cronTaskWithScopedProxy() {
void cronTaskWithScopedProxy() {
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
context.registerBeanDefinition("postProcessor", processorDefinition);
new AnnotatedBeanDefinitionReader(context).register(ProxiedCronTestBean.class, ProxiedCronTestBeanDependent.class);
@@ -525,7 +384,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
@Test
public void metaAnnotationWithFixedRate() {
void metaAnnotationWithFixedRate() {
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
BeanDefinition targetDefinition = new RootBeanDefinition(MetaAnnotationFixedRateTestBean.class);
context.registerBeanDefinition("postProcessor", processorDefinition);
@@ -552,7 +411,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
@Test
public void composedAnnotationWithInitialDelayAndFixedRate() {
void composedAnnotationWithInitialDelayAndFixedRate() {
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
BeanDefinition targetDefinition = new RootBeanDefinition(ComposedAnnotationFixedRateTestBean.class);
context.registerBeanDefinition("postProcessor", processorDefinition);
@@ -580,7 +439,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
@Test
public void metaAnnotationWithCronExpression() {
void metaAnnotationWithCronExpression() {
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
BeanDefinition targetDefinition = new RootBeanDefinition(MetaAnnotationCronTestBean.class);
context.registerBeanDefinition("postProcessor", processorDefinition);
@@ -607,7 +466,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
@Test
public void propertyPlaceholderWithCron() {
void propertyPlaceholderWithCron() {
String businessHoursCronExpression = "0 0 9-17 * * MON-FRI";
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
BeanDefinition placeholderDefinition = new RootBeanDefinition(PropertySourcesPlaceholderConfigurer.class);
@@ -640,7 +499,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
@Test
public void propertyPlaceholderWithInactiveCron() {
void propertyPlaceholderWithInactiveCron() {
String businessHoursCronExpression = "-";
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
BeanDefinition placeholderDefinition = new RootBeanDefinition(PropertySourcesPlaceholderConfigurer.class);
@@ -657,24 +516,23 @@ public class ScheduledAnnotationBeanPostProcessorTests {
assertThat(postProcessor.getScheduledTasks().isEmpty()).isTrue();
}
@Test
public void propertyPlaceholderWithFixedDelayInMillis() {
propertyPlaceholderWithFixedDelay(false);
}
@ParameterizedTest
@CsvSource({
"PropertyPlaceholderWithFixedDelay, 5000, 1000, 5000, 1000",
"PropertyPlaceholderWithFixedDelay, PT5S, PT1S, 5000, 1000",
"PropertyPlaceholderWithFixedDelayInSeconds, 5000, 1000, 5000000, 1000000",
"PropertyPlaceholderWithFixedDelayInSeconds, PT5S, PT1S, 5000, 1000"
})
void propertyPlaceholderWithFixedDelay(@NameToClass Class<?> beanClass, String fixedDelay, String initialDelay,
long expectedInterval, long expectedInitialDelay) {
@Test
public void propertyPlaceholderWithFixedDelayInDuration() {
propertyPlaceholderWithFixedDelay(true);
}
private void propertyPlaceholderWithFixedDelay(boolean durationFormat) {
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
BeanDefinition placeholderDefinition = new RootBeanDefinition(PropertySourcesPlaceholderConfigurer.class);
Properties properties = new Properties();
properties.setProperty("fixedDelay", (durationFormat ? "PT5S" : "5000"));
properties.setProperty("initialDelay", (durationFormat ? "PT1S" : "1000"));
properties.setProperty("fixedDelay", fixedDelay);
properties.setProperty("initialDelay", initialDelay);
placeholderDefinition.getPropertyValues().addPropertyValue("properties", properties);
BeanDefinition targetDefinition = new RootBeanDefinition(PropertyPlaceholderWithFixedDelayTestBean.class);
BeanDefinition targetDefinition = new RootBeanDefinition(beanClass);
context.registerBeanDefinition("postProcessor", processorDefinition);
context.registerBeanDefinition("placeholder", placeholderDefinition);
context.registerBeanDefinition("target", targetDefinition);
@@ -696,28 +554,29 @@ public class ScheduledAnnotationBeanPostProcessorTests {
Method targetMethod = runnable.getMethod();
assertThat(targetObject).isEqualTo(target);
assertThat(targetMethod.getName()).isEqualTo("fixedDelay");
assertThat(task.getInitialDelay()).isEqualTo(1000L);
assertThat(task.getInterval()).isEqualTo(5000L);
assertSoftly(softly -> {
softly.assertThat(task.getInitialDelay()).as("initial delay").isEqualTo(expectedInitialDelay);
softly.assertThat(task.getInterval()).as("interval").isEqualTo(expectedInterval);
});
}
@Test
public void propertyPlaceholderWithFixedRateInMillis() {
propertyPlaceholderWithFixedRate(false);
}
@ParameterizedTest
@CsvSource({
"PropertyPlaceholderWithFixedRate, 3000, 1000, 3000, 1000",
"PropertyPlaceholderWithFixedRate, PT3S, PT1S, 3000, 1000",
"PropertyPlaceholderWithFixedRateInSeconds, 3000, 1000, 3000000, 1000000",
"PropertyPlaceholderWithFixedRateInSeconds, PT3S, PT1S, 3000, 1000"
})
void propertyPlaceholderWithFixedRate(@NameToClass Class<?> beanClass, String fixedRate, String initialDelay,
long expectedInterval, long expectedInitialDelay) {
@Test
public void propertyPlaceholderWithFixedRateInDuration() {
propertyPlaceholderWithFixedRate(true);
}
private void propertyPlaceholderWithFixedRate(boolean durationFormat) {
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
BeanDefinition placeholderDefinition = new RootBeanDefinition(PropertySourcesPlaceholderConfigurer.class);
Properties properties = new Properties();
properties.setProperty("fixedRate", (durationFormat ? "PT3S" : "3000"));
properties.setProperty("initialDelay", (durationFormat ? "PT1S" : "1000"));
properties.setProperty("fixedRate", fixedRate);
properties.setProperty("initialDelay", initialDelay);
placeholderDefinition.getPropertyValues().addPropertyValue("properties", properties);
BeanDefinition targetDefinition = new RootBeanDefinition(PropertyPlaceholderWithFixedRateTestBean.class);
BeanDefinition targetDefinition = new RootBeanDefinition(beanClass);
context.registerBeanDefinition("postProcessor", processorDefinition);
context.registerBeanDefinition("placeholder", placeholderDefinition);
context.registerBeanDefinition("target", targetDefinition);
@@ -739,12 +598,14 @@ public class ScheduledAnnotationBeanPostProcessorTests {
Method targetMethod = runnable.getMethod();
assertThat(targetObject).isEqualTo(target);
assertThat(targetMethod.getName()).isEqualTo("fixedRate");
assertThat(task.getInitialDelay()).isEqualTo(1000L);
assertThat(task.getInterval()).isEqualTo(3000L);
assertSoftly(softly -> {
softly.assertThat(task.getInitialDelay()).as("initial delay").isEqualTo(expectedInitialDelay);
softly.assertThat(task.getInterval()).as("interval").isEqualTo(expectedInterval);
});
}
@Test
public void expressionWithCron() {
void expressionWithCron() {
String businessHoursCronExpression = "0 0 9-17 * * MON-FRI";
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
BeanDefinition targetDefinition = new RootBeanDefinition(ExpressionWithCronTestBean.class);
@@ -775,7 +636,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
@Test
public void propertyPlaceholderForMetaAnnotation() {
void propertyPlaceholderForMetaAnnotation() {
String businessHoursCronExpression = "0 0 9-17 * * MON-FRI";
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
BeanDefinition placeholderDefinition = new RootBeanDefinition(PropertySourcesPlaceholderConfigurer.class);
@@ -808,7 +669,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
@Test
public void nonVoidReturnType() {
void nonVoidReturnType() {
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
BeanDefinition targetDefinition = new RootBeanDefinition(NonVoidReturnTypeTestBean.class);
context.registerBeanDefinition("postProcessor", processorDefinition);
@@ -835,7 +696,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
@Test
public void emptyAnnotation() {
void emptyAnnotation() {
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
BeanDefinition targetDefinition = new RootBeanDefinition(EmptyAnnotationTestBean.class);
context.registerBeanDefinition("postProcessor", processorDefinition);
@@ -845,7 +706,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
@Test
public void invalidCron() throws Throwable {
void invalidCron() throws Throwable {
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
BeanDefinition targetDefinition = new RootBeanDefinition(InvalidCronTestBean.class);
context.registerBeanDefinition("postProcessor", processorDefinition);
@@ -855,7 +716,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
@Test
public void nonEmptyParamList() {
void nonEmptyParamList() {
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
BeanDefinition targetDefinition = new RootBeanDefinition(NonEmptyParamListTestBean.class);
context.registerBeanDefinition("postProcessor", processorDefinition);
@@ -865,70 +726,68 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
static class FixedDelayTestBean {
static class FixedDelay {
@Scheduled(fixedDelay = 5000)
public void fixedDelay() {
void fixedDelay() {
}
}
static class FixedDelayWithSecondsTimeUnitTestBean {
static class FixedDelayInSeconds {
@Scheduled(fixedDelay = 5, timeUnit = TimeUnit.SECONDS)
public void fixedDelay() {
void fixedDelay() {
}
}
static class FixedDelayWithMinutesTimeUnitTestBean {
static class FixedDelayInMinutes {
@Scheduled(fixedDelay = 3, timeUnit = TimeUnit.MINUTES)
public void fixedDelay() {
void fixedDelay() {
}
}
static class FixedRateTestBean {
static class FixedRate {
@Scheduled(fixedRate = 3000)
public void fixedRate() {
void fixedRate() {
}
}
static class FixedRateWithSecondsTimeUnitTestBean {
static class FixedRateInSeconds {
@Scheduled(fixedRate = 5, timeUnit = TimeUnit.SECONDS)
public void fixedRate() {
void fixedRate() {
}
}
static class FixedRateWithMinutesTimeUnitTestBean {
static class FixedRateInMinutes {
@Scheduled(fixedRate = 3, timeUnit = TimeUnit.MINUTES)
public void fixedRate() {
void fixedRate() {
}
}
static class FixedRateWithInitialDelayTestBean {
static class FixedRateWithInitialDelay {
@Scheduled(fixedRate = 3000, initialDelay = 1000)
public void fixedRate() {
void fixedRate() {
}
}
static class FixedRateWithSecondsTimeUnitInitialDelayTestBean {
static class FixedRateWithInitialDelayInSeconds {
@Scheduled(fixedRate = 3, initialDelay = 5, timeUnit = TimeUnit.SECONDS)
public void fixedRate() {
void fixedRate() {
}
}
static class FixedRateWithMinutesTimeUnitInitialDelayTestBean {
static class FixedRateWithInitialDelayInMinutes {
@Scheduled(fixedRate = 3, initialDelay = 1, timeUnit = TimeUnit.MINUTES)
public void fixedRate() {
void fixedRate() {
}
}
@@ -936,7 +795,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
static class SeveralFixedRatesWithSchedulesContainerAnnotationTestBean {
@Schedules({@Scheduled(fixedRate = 4000), @Scheduled(fixedRate = 4000, initialDelay = 2000)})
public void fixedRate() {
void fixedRate() {
}
}
@@ -945,7 +804,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
@Scheduled(fixedRate = 4000)
@Scheduled(fixedRate = 4000, initialDelay = 2000)
public void fixedRate() {
void fixedRate() {
}
static SeveralFixedRatesWithRepeatedScheduledAnnotationTestBean nestedProxy() {
@@ -962,7 +821,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
@Scheduled(fixedRate = 4000)
@Scheduled(fixedRate = 4000, initialDelay = 2000)
public void fixedRate() {
void fixedRate() {
}
}
@@ -1006,7 +865,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
static class CronWithInvalidTimezoneTestBean {
@Scheduled(cron = "0 0 0-4,6-23 * * ?", zone = "FOO")
public void cron() throws IOException {
void cron() throws IOException {
throw new IOException("no no no");
}
}
@@ -1017,7 +876,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
static class ProxiedCronTestBean {
@Scheduled(cron = "*/7 * * * * ?")
public void cron() throws IOException {
void cron() throws IOException {
throw new IOException("no no no");
}
}
@@ -1025,7 +884,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
static class ProxiedCronTestBeanDependent {
public ProxiedCronTestBeanDependent(ProxiedCronTestBean testBean) {
ProxiedCronTestBeanDependent(ProxiedCronTestBean testBean) {
}
}
@@ -1033,7 +892,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
static class NonVoidReturnTypeTestBean {
@Scheduled(cron = "0 0 9-17 * * MON-FRI")
public String cron() {
String cron() {
return "oops";
}
}
@@ -1042,7 +901,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
static class EmptyAnnotationTestBean {
@Scheduled
public void invalid() {
void invalid() {
}
}
@@ -1050,7 +909,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
static class InvalidCronTestBean {
@Scheduled(cron = "abc")
public void invalid() {
void invalid() {
}
}
@@ -1058,7 +917,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
static class NonEmptyParamListTestBean {
@Scheduled(fixedRate = 3000)
public void invalid(String oops) {
void invalid(String oops) {
}
}
@@ -1090,7 +949,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
static class MetaAnnotationFixedRateTestBean {
@EveryFiveSeconds
public void checkForUpdates() {
void checkForUpdates() {
}
}
@@ -1098,7 +957,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
static class ComposedAnnotationFixedRateTestBean {
@WaitASec(fixedRate = 5000)
public void checkForUpdates() {
void checkForUpdates() {
}
}
@@ -1106,7 +965,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
static class MetaAnnotationCronTestBean {
@Hourly
public void generateReport() {
void generateReport() {
}
}
@@ -1114,23 +973,37 @@ public class ScheduledAnnotationBeanPostProcessorTests {
static class PropertyPlaceholderWithCronTestBean {
@Scheduled(cron = "${schedules.businessHours}")
public void x() {
void x() {
}
}
static class PropertyPlaceholderWithFixedDelayTestBean {
static class PropertyPlaceholderWithFixedDelay {
@Scheduled(fixedDelayString = "${fixedDelay}", initialDelayString = "${initialDelay}")
public void fixedDelay() {
void fixedDelay() {
}
}
static class PropertyPlaceholderWithFixedDelayInSeconds {
@Scheduled(fixedDelayString = "${fixedDelay}", initialDelayString = "${initialDelay}", timeUnit = TimeUnit.SECONDS)
void fixedDelay() {
}
}
static class PropertyPlaceholderWithFixedRateTestBean {
static class PropertyPlaceholderWithFixedRate {
@Scheduled(fixedRateString = "${fixedRate}", initialDelayString = "${initialDelay}")
public void fixedRate() {
void fixedRate() {
}
}
static class PropertyPlaceholderWithFixedRateInSeconds {
@Scheduled(fixedRateString = "${fixedRate}", initialDelayString = "${initialDelay}", timeUnit = TimeUnit.SECONDS)
void fixedRate() {
}
}
@@ -1138,7 +1011,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
static class ExpressionWithCronTestBean {
@Scheduled(cron = "#{schedules.businessHours}")
public void x() {
void x() {
}
}
@@ -1153,7 +1026,24 @@ public class ScheduledAnnotationBeanPostProcessorTests {
static class PropertyPlaceholderMetaAnnotationTestBean {
@BusinessHours
public void y() {
void y() {
}
}
@Retention(RetentionPolicy.RUNTIME)
@ConvertWith(NameToClass.Converter.class)
private @interface NameToClass {
class Converter implements ArgumentConverter {
@Override
public Class<?> convert(Object beanClassName, ParameterContext context) throws ArgumentConversionException {
try {
String name = getClass().getEnclosingClass().getEnclosingClass().getName() + "$" + beanClassName;
return getClass().getClassLoader().loadClass(name);
}
catch (Exception ex) {
throw new ArgumentConversionException("Failed to convert class name to Class", ex);
}
}
}
}