Skip to content

Commit 9f10c20

Browse files
authored
Merge pull request lukas-krecan#25 from lukas-krecan/composedannotation
Support for composed annotations
2 parents c8d6db5 + 0df8d51 commit 9f10c20

File tree

4 files changed

+48
-5
lines changed

4 files changed

+48
-5
lines changed

shedlock-core/src/main/java/net/javacrumbs/shedlock/core/LockConfiguration.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ public LockConfiguration(String name, Instant lockUntil, Instant lockAtLeastUnti
4848
if (lockAtMostUntil.isBefore(Instant.now())) {
4949
throw new IllegalArgumentException("lockAtMost is in the past for lock '" + name + "'.");
5050
}
51+
if (name.isEmpty()) {
52+
throw new IllegalArgumentException("lock name can not be empty");
53+
}
5154
}
5255

5356
public String getName() {

shedlock-core/src/main/java/net/javacrumbs/shedlock/core/SchedulerLock.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@
2020
import java.lang.annotation.RetentionPolicy;
2121
import java.lang.annotation.Target;
2222

23-
@Target({ElementType.METHOD})
23+
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
2424
@Retention(RetentionPolicy.RUNTIME)
2525
public @interface SchedulerLock {
2626
/**
2727
* Lock name.
2828
*/
29-
String name();
29+
String name() default "";
3030

3131
/**
3232
* How long (in ms) the lock should be kept in case the machine which obtained the lock died before releasing it.

shedlock-spring/src/main/java/net/javacrumbs/shedlock/spring/SpringLockConfigurationExtractor.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
import org.slf4j.Logger;
2222
import org.slf4j.LoggerFactory;
2323
import org.springframework.aop.support.AopUtils;
24-
import org.springframework.core.annotation.AnnotationUtils;
24+
import org.springframework.core.annotation.AnnotatedElementUtils;
2525
import org.springframework.scheduling.support.ScheduledMethodRunnable;
2626
import org.springframework.util.StringUtils;
2727
import org.springframework.util.StringValueResolver;
@@ -101,7 +101,7 @@ public Optional<LockConfiguration> getLockConfiguration(Runnable task) {
101101

102102
SchedulerLock findAnnotation(ScheduledMethodRunnable task) {
103103
Method method = task.getMethod();
104-
SchedulerLock annotation = AnnotationUtils.findAnnotation(method, SchedulerLock.class);
104+
SchedulerLock annotation = findAnnotation(method);
105105
if (annotation != null) {
106106
return annotation;
107107
} else {
@@ -111,7 +111,7 @@ SchedulerLock findAnnotation(ScheduledMethodRunnable task) {
111111
try {
112112
Method methodOnTarget = targetClass
113113
.getMethod(method.getName(), method.getParameterTypes());
114-
return AnnotationUtils.findAnnotation(methodOnTarget, SchedulerLock.class);
114+
return findAnnotation(methodOnTarget);
115115
} catch (NoSuchMethodException e) {
116116
return null;
117117
}
@@ -121,6 +121,10 @@ SchedulerLock findAnnotation(ScheduledMethodRunnable task) {
121121
}
122122
}
123123

124+
private SchedulerLock findAnnotation(Method method) {
125+
return AnnotatedElementUtils.getMergedAnnotation(method, SchedulerLock.class);
126+
}
127+
124128
TemporalAmount getLockAtMostFor(SchedulerLock annotation) {
125129
return getValue(
126130
annotation.lockAtMostFor(),

shedlock-spring/src/test/java/net/javacrumbs/shedlock/spring/SpringLockConfigurationExtractorTest.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,21 @@
2222
import net.javacrumbs.shedlock.spring.proxytest.SubclassProxyConfig;
2323
import org.junit.Test;
2424
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
25+
import org.springframework.core.annotation.AliasFor;
26+
import org.springframework.scheduling.annotation.Scheduled;
2527
import org.springframework.scheduling.support.ScheduledMethodRunnable;
2628
import org.springframework.util.StringValueResolver;
2729

30+
import java.lang.annotation.Documented;
31+
import java.lang.annotation.Retention;
32+
import java.lang.annotation.Target;
2833
import java.time.Duration;
2934
import java.time.temporal.ChronoUnit;
3035
import java.time.temporal.TemporalAmount;
3136
import java.util.Optional;
3237

38+
import static java.lang.annotation.ElementType.METHOD;
39+
import static java.lang.annotation.RetentionPolicy.RUNTIME;
3340
import static java.time.Instant.now;
3441
import static java.time.temporal.ChronoUnit.MILLIS;
3542
import static java.time.temporal.ChronoUnit.SECONDS;
@@ -104,6 +111,14 @@ public void shouldGetPositiveGracePeriodFromAnnotationWithString() throws NoSuch
104111
assertThat(gracePeriod).isEqualTo(Duration.of(10, MILLIS));
105112
}
106113

114+
@Test
115+
public void shouldExtractComposedAnnotation() throws NoSuchMethodException {
116+
SchedulerLock annotation = getAnnotation("composedAnnotation");
117+
TemporalAmount atMostFor = extractor.getLockAtMostFor(annotation);
118+
assertThat(annotation.name()).isEqualTo("lockName1");
119+
assertThat(atMostFor).isEqualTo(Duration.of(20, MILLIS));
120+
}
121+
107122
@Test
108123
public void shouldFindAnnotationOnDynamicProxy() throws NoSuchMethodException {
109124
doTestfindAnnotationOnProxy(DynamicProxyConfig.class);
@@ -158,4 +173,25 @@ public void annotatedMethodWithPositiveGracePeriod() {
158173
public void annotatedMethodWithPositiveGracePeriodWithString() {
159174

160175
}
176+
177+
@ScheduledLocked(name = "lockName1")
178+
public void composedAnnotation() {
179+
180+
}
181+
182+
@Target(METHOD)
183+
@Retention(RUNTIME)
184+
@Documented
185+
@Scheduled
186+
@SchedulerLock
187+
public @interface ScheduledLocked {
188+
@AliasFor(annotation = Scheduled.class, attribute = "cron")
189+
String cron() default "";
190+
191+
@AliasFor(annotation = SchedulerLock.class, attribute = "lockAtMostFor")
192+
long lockAtMostFor() default 20L;
193+
194+
@AliasFor(annotation = SchedulerLock.class, attribute = "name")
195+
String name();
196+
}
161197
}

0 commit comments

Comments
 (0)