From aa99ebd5fdd43f48f825c1742a32d86590072ab4 Mon Sep 17 00:00:00 2001 From: Lukas Krecan Date: Wed, 25 Mar 2020 09:23:33 +0100 Subject: [PATCH] #208 Support for meta annotations --- .../aop/MethodProxyScheduledLockAdvisor.java | 19 +++++++++---- .../aop/AbstractSchedulerProxyTest.java | 14 ++++++++++ .../aop/DeprecatedMethodProxyAopConfig.java | 20 ++++++++++++++ .../aop/DeprecatedMethodProxyAopTest.java | 7 +++++ .../spring/aop/MethodProxyAopConfig.java | 5 ++++ .../spring/aop/MethodProxyAopTest.java | 8 ++++++ .../shedlock/spring/aop/MyScheduled.java | 27 +++++++++++++++++++ 7 files changed, 95 insertions(+), 5 deletions(-) create mode 100644 spring/shedlock-spring/src/test/java/net/javacrumbs/shedlock/spring/aop/MyScheduled.java diff --git a/spring/shedlock-spring/src/main/java/net/javacrumbs/shedlock/spring/aop/MethodProxyScheduledLockAdvisor.java b/spring/shedlock-spring/src/main/java/net/javacrumbs/shedlock/spring/aop/MethodProxyScheduledLockAdvisor.java index ddf742bb3..867ce5882 100644 --- a/spring/shedlock-spring/src/main/java/net/javacrumbs/shedlock/spring/aop/MethodProxyScheduledLockAdvisor.java +++ b/spring/shedlock-spring/src/main/java/net/javacrumbs/shedlock/spring/aop/MethodProxyScheduledLockAdvisor.java @@ -18,7 +18,7 @@ import net.javacrumbs.shedlock.core.LockConfiguration; import net.javacrumbs.shedlock.core.LockingTaskExecutor; import net.javacrumbs.shedlock.core.LockingTaskExecutor.TaskResult; -import net.javacrumbs.shedlock.core.SchedulerLock; +import net.javacrumbs.shedlock.spring.annotation.SchedulerLock; import org.aopalliance.aop.Advice; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; @@ -26,14 +26,14 @@ import org.springframework.aop.Pointcut; import org.springframework.aop.support.AbstractPointcutAdvisor; import org.springframework.aop.support.ComposablePointcut; +import org.springframework.aop.support.annotation.AnnotationMatchingPointcut; +import java.lang.annotation.Annotation; import java.util.Optional; -import static org.springframework.aop.support.annotation.AnnotationMatchingPointcut.forMethodAnnotation; - class MethodProxyScheduledLockAdvisor extends AbstractPointcutAdvisor { - private final Pointcut pointcut = new ComposablePointcut(forMethodAnnotation(SchedulerLock.class)) - .union(forMethodAnnotation(net.javacrumbs.shedlock.spring.annotation.SchedulerLock.class)); + private final Pointcut pointcut = new ComposablePointcut(methodPointcutFor(net.javacrumbs.shedlock.core.SchedulerLock.class)) + .union(methodPointcutFor(SchedulerLock.class)); private final Advice advice; @@ -41,6 +41,15 @@ class MethodProxyScheduledLockAdvisor extends AbstractPointcutAdvisor { this.advice = new LockingInterceptor(lockConfigurationExtractor, lockingTaskExecutor); } + @NotNull + private static AnnotationMatchingPointcut methodPointcutFor(Class methodAnnotationType) { + return new AnnotationMatchingPointcut( + null, + methodAnnotationType, + true + ); + } + /** * Get the Pointcut that drives this advisor. */ diff --git a/spring/shedlock-spring/src/test/java/net/javacrumbs/shedlock/spring/aop/AbstractSchedulerProxyTest.java b/spring/shedlock-spring/src/test/java/net/javacrumbs/shedlock/spring/aop/AbstractSchedulerProxyTest.java index 05379653c..0865b80ee 100644 --- a/spring/shedlock-spring/src/test/java/net/javacrumbs/shedlock/spring/aop/AbstractSchedulerProxyTest.java +++ b/spring/shedlock-spring/src/test/java/net/javacrumbs/shedlock/spring/aop/AbstractSchedulerProxyTest.java @@ -81,6 +81,15 @@ public void shouldCallLockProviderOnSchedulerCallDeprecatedAnnotation() throws N verify(simpleLock).unlock(); } + @Test + public void shouldUseCustomAnnotation() throws NoSuchMethodException, ExecutionException, InterruptedException { + Runnable task = task("custom"); + taskScheduler.schedule(task, now()).get(); + verify(lockProvider).lock(hasParams("custom", 60_000, 1_000)); + verify(simpleLock).unlock(); + } + + @Test public void shouldUserPropertyName() throws NoSuchMethodException, ExecutionException, InterruptedException { Runnable task = task("spelMethod"); @@ -134,6 +143,11 @@ public void annotatedMethod() { assertRightSchedulerUsed(); } + @MyScheduled(name = "custom", lockAtMostFor = "1m", lockAtLeastFor = "1s") + public void custom() { + assertRightSchedulerUsed(); + } + @SchedulerLock(name = "${property.value}", lockAtMostFor = "1000", lockAtLeastFor = "500") public void spelMethod() { diff --git a/spring/shedlock-spring/src/test/java/net/javacrumbs/shedlock/spring/aop/DeprecatedMethodProxyAopConfig.java b/spring/shedlock-spring/src/test/java/net/javacrumbs/shedlock/spring/aop/DeprecatedMethodProxyAopConfig.java index e93ed6679..c00a35f1e 100644 --- a/spring/shedlock-spring/src/test/java/net/javacrumbs/shedlock/spring/aop/DeprecatedMethodProxyAopConfig.java +++ b/spring/shedlock-spring/src/test/java/net/javacrumbs/shedlock/spring/aop/DeprecatedMethodProxyAopConfig.java @@ -22,9 +22,15 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; +import org.springframework.core.annotation.AliasFor; import org.springframework.scheduling.annotation.EnableScheduling; import java.io.IOException; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import static org.mockito.Mockito.mock; @@ -32,6 +38,7 @@ @EnableScheduling @EnableSchedulerLock(defaultLockAtMostFor = "${default.lock_at_most_for}", defaultLockAtLeastFor = "${default.lock_at_least_for}") @PropertySource("test.properties") +@SuppressWarnings("deprecation") public class DeprecatedMethodProxyAopConfig { @Bean @@ -58,6 +65,10 @@ public void noAnnotation() { public void normal() { } + @MyDeprecatedScheduled(name = "custom") + public void custom() { + } + @SchedulerLock(name = "runtimeException", lockAtMostFor = 100) public Void throwsRuntimeException() { throw new RuntimeException(); @@ -79,6 +90,15 @@ public void spel() { } } + @Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) + @Retention(RetentionPolicy.RUNTIME) + @Documented + @SchedulerLock + public @interface MyDeprecatedScheduled { + @AliasFor(annotation = SchedulerLock.class, attribute = "name") + String name(); + } + interface AnotherTestBean { void runManually(); } diff --git a/spring/shedlock-spring/src/test/java/net/javacrumbs/shedlock/spring/aop/DeprecatedMethodProxyAopTest.java b/spring/shedlock-spring/src/test/java/net/javacrumbs/shedlock/spring/aop/DeprecatedMethodProxyAopTest.java index 79feef17c..354ef132a 100644 --- a/spring/shedlock-spring/src/test/java/net/javacrumbs/shedlock/spring/aop/DeprecatedMethodProxyAopTest.java +++ b/spring/shedlock-spring/src/test/java/net/javacrumbs/shedlock/spring/aop/DeprecatedMethodProxyAopTest.java @@ -73,6 +73,13 @@ public void shouldCallLockProviderOnDirectCall() { verify(simpleLock).unlock(); } + @Test + public void shouldUseCustomAnnotation() { + testBean.custom(); + verify(lockProvider).lock(hasParams("custom", 30_000, 100)); + verify(simpleLock).unlock(); + } + @Test public void shouldRethrowRuntimeException() { assertThatThrownBy(() -> testBean.throwsRuntimeException()).isInstanceOf(RuntimeException.class); diff --git a/spring/shedlock-spring/src/test/java/net/javacrumbs/shedlock/spring/aop/MethodProxyAopConfig.java b/spring/shedlock-spring/src/test/java/net/javacrumbs/shedlock/spring/aop/MethodProxyAopConfig.java index 58e976130..32b9f50ec 100644 --- a/spring/shedlock-spring/src/test/java/net/javacrumbs/shedlock/spring/aop/MethodProxyAopConfig.java +++ b/spring/shedlock-spring/src/test/java/net/javacrumbs/shedlock/spring/aop/MethodProxyAopConfig.java @@ -72,6 +72,11 @@ public void normal() { called.set(true); } + @MyScheduled(name = "custom", lockAtMostFor = "1m", lockAtLeastFor = "1s") + public void custom() { + called.set(true); + } + @SchedulerLock(name = "runtimeException", lockAtMostFor = "100") public Void throwsRuntimeException() { called.set(true); diff --git a/spring/shedlock-spring/src/test/java/net/javacrumbs/shedlock/spring/aop/MethodProxyAopTest.java b/spring/shedlock-spring/src/test/java/net/javacrumbs/shedlock/spring/aop/MethodProxyAopTest.java index 798e9c6dd..b998e653a 100644 --- a/spring/shedlock-spring/src/test/java/net/javacrumbs/shedlock/spring/aop/MethodProxyAopTest.java +++ b/spring/shedlock-spring/src/test/java/net/javacrumbs/shedlock/spring/aop/MethodProxyAopTest.java @@ -75,6 +75,14 @@ public void shouldCallLockProviderOnDirectCall() { assertThat(testBean.wasMethodCalled()).isTrue(); } + @Test + public void shouldUseCustomAnnotation() { + testBean.custom(); + verify(lockProvider).lock(hasParams("custom", 60_000, 1_000)); + verify(simpleLock).unlock(); + assertThat(testBean.wasMethodCalled()).isTrue(); + } + @Test public void shouldRethrowRuntimeException() { assertThatThrownBy(() -> testBean.throwsRuntimeException()).isInstanceOf(RuntimeException.class); diff --git a/spring/shedlock-spring/src/test/java/net/javacrumbs/shedlock/spring/aop/MyScheduled.java b/spring/shedlock-spring/src/test/java/net/javacrumbs/shedlock/spring/aop/MyScheduled.java new file mode 100644 index 000000000..6947bed1e --- /dev/null +++ b/spring/shedlock-spring/src/test/java/net/javacrumbs/shedlock/spring/aop/MyScheduled.java @@ -0,0 +1,27 @@ +package net.javacrumbs.shedlock.spring.aop; + +import net.javacrumbs.shedlock.spring.annotation.SchedulerLock; +import org.springframework.core.annotation.AliasFor; +import org.springframework.scheduling.annotation.Async; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Async +@SchedulerLock +public @interface MyScheduled { + @AliasFor(annotation = SchedulerLock.class, attribute = "name") + String name(); + + @AliasFor(annotation = SchedulerLock.class, attribute = "lockAtMostFor") + String lockAtMostFor() default ""; + + @AliasFor(annotation = SchedulerLock.class, attribute = "lockAtLeastFor") + String lockAtLeastFor() default ""; +}