Skip to content

Commit b5a56ca

Browse files
committed
CronSequenceGenerator explicitly rejects invalid incrementer delta
Issue: SPR-12871 (cherry picked from commit 50f4977)
1 parent dd73848 commit b5a56ca

File tree

3 files changed

+70
-42
lines changed

3 files changed

+70
-42
lines changed

spring-context/src/main/java/org/springframework/scheduling/support/CronSequenceGenerator.java

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -29,7 +29,8 @@
2929
import org.springframework.util.StringUtils;
3030

3131
/**
32-
* Date sequence generator for a <a href="http://www.manpagez.com/man/5/crontab/">Crontab pattern</a>,
32+
* Date sequence generator for a
33+
* <a href="http://www.manpagez.com/man/5/crontab/">Crontab pattern</a>,
3334
* allowing clients to specify a pattern that the sequence matches.
3435
*
3536
* <p>The pattern is a list of six single space-separated fields: representing
@@ -53,21 +54,21 @@
5354
*/
5455
public class CronSequenceGenerator {
5556

56-
private final BitSet seconds = new BitSet(60);
57-
58-
private final BitSet minutes = new BitSet(60);
57+
private final String expression;
5958

60-
private final BitSet hours = new BitSet(24);
59+
private final TimeZone timeZone;
6160

62-
private final BitSet daysOfWeek = new BitSet(7);
61+
private final BitSet months = new BitSet(12);
6362

6463
private final BitSet daysOfMonth = new BitSet(31);
6564

66-
private final BitSet months = new BitSet(12);
65+
private final BitSet daysOfWeek = new BitSet(7);
6766

68-
private final String expression;
67+
private final BitSet hours = new BitSet(24);
6968

70-
private final TimeZone timeZone;
69+
private final BitSet minutes = new BitSet(60);
70+
71+
private final BitSet seconds = new BitSet(60);
7172

7273

7374
/**
@@ -95,6 +96,14 @@ public CronSequenceGenerator(String expression, TimeZone timeZone) {
9596
}
9697

9798

99+
/**
100+
* Return the cron pattern that this sequence generator has been built for.
101+
*/
102+
String getExpression() {
103+
return this.expression;
104+
}
105+
106+
98107
/**
99108
* Get the next {@link Date} in the sequence matching the Cron pattern and
100109
* after the value provided. The return value will have a whole number of
@@ -271,9 +280,9 @@ private void parse(String expression) throws IllegalArgumentException {
271280
}
272281

273282
/**
274-
* Replace the values in the commaSeparatedList (case insensitive) with
275-
* their index in the list.
276-
* @return a new string with the values from the list replaced
283+
* Replace the values in the comma-separated list (case insensitive)
284+
* with their index in the list.
285+
* @return a new String with the values from the list replaced
277286
*/
278287
private String replaceOrdinals(String value, String commaSeparatedList) {
279288
String[] list = StringUtils.commaDelimitedListToStringArray(commaSeparatedList);
@@ -332,6 +341,10 @@ private void setNumberHits(BitSet bits, String value, int min, int max) {
332341
range[1] = max - 1;
333342
}
334343
int delta = Integer.valueOf(split[1]);
344+
if (delta <= 0) {
345+
throw new IllegalArgumentException("Incrementer delta must be 1 or higher: '" +
346+
field + "' in expression \"" + this.expression + "\"");
347+
}
335348
for (int i = range[0]; i <= range[1]; i += delta) {
336349
bits.set(i);
337350
}
@@ -369,30 +382,30 @@ private int[] getRange(String field, int min, int max) {
369382
return result;
370383
}
371384

372-
String getExpression() {
373-
return this.expression;
374-
}
375385

376386
@Override
377-
public boolean equals(Object obj) {
378-
if (!(obj instanceof CronSequenceGenerator)) {
387+
public boolean equals(Object other) {
388+
if (this == other) {
389+
return true;
390+
}
391+
if (!(other instanceof CronSequenceGenerator)) {
379392
return false;
380393
}
381-
CronSequenceGenerator cron = (CronSequenceGenerator) obj;
382-
return cron.months.equals(this.months) && cron.daysOfMonth.equals(this.daysOfMonth)
383-
&& cron.daysOfWeek.equals(this.daysOfWeek) && cron.hours.equals(this.hours)
384-
&& cron.minutes.equals(this.minutes) && cron.seconds.equals(this.seconds);
394+
CronSequenceGenerator otherCron = (CronSequenceGenerator) other;
395+
return (this.months.equals(otherCron.months) && this.daysOfMonth.equals(otherCron.daysOfMonth) &&
396+
this.daysOfWeek.equals(otherCron.daysOfWeek) && this.hours.equals(otherCron.hours) &&
397+
this.minutes.equals(otherCron.minutes) && this.seconds.equals(otherCron.seconds));
385398
}
386399

387400
@Override
388401
public int hashCode() {
389-
return 37 + 17 * this.months.hashCode() + 29 * this.daysOfMonth.hashCode() + 37 * this.daysOfWeek.hashCode()
390-
+ 41 * this.hours.hashCode() + 53 * this.minutes.hashCode() + 61 * this.seconds.hashCode();
402+
return (17 * this.months.hashCode() + 29 * this.daysOfMonth.hashCode() + 37 * this.daysOfWeek.hashCode() +
403+
41 * this.hours.hashCode() + 53 * this.minutes.hashCode() + 61 * this.seconds.hashCode());
391404
}
392405

393406
@Override
394407
public String toString() {
395-
return getClass().getSimpleName() + ": " + this.expression;
408+
return (getClass().getSimpleName() + ": " + this.expression);
396409
}
397410

398411
}

spring-context/src/main/java/org/springframework/scheduling/support/CronTrigger.java

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -37,21 +37,29 @@ public class CronTrigger implements Trigger {
3737

3838
/**
3939
* Build a {@link CronTrigger} from the pattern provided in the default time zone.
40-
* @param cronExpression a space-separated list of time fields,
41-
* following cron expression conventions
40+
* @param expression a space-separated list of time fields, following cron
41+
* expression conventions
4242
*/
43-
public CronTrigger(String cronExpression) {
44-
this.sequenceGenerator = new CronSequenceGenerator(cronExpression);
43+
public CronTrigger(String expression) {
44+
this.sequenceGenerator = new CronSequenceGenerator(expression);
4545
}
4646

4747
/**
48-
* Build a {@link CronTrigger} from the pattern provided.
49-
* @param cronExpression a space-separated list of time fields,
50-
* following cron expression conventions
48+
* Build a {@link CronTrigger} from the pattern provided in the given time zone.
49+
* @param expression a space-separated list of time fields, following cron
50+
* expression conventions
5151
* @param timeZone a time zone in which the trigger times will be generated
5252
*/
53-
public CronTrigger(String cronExpression, TimeZone timeZone) {
54-
this.sequenceGenerator = new CronSequenceGenerator(cronExpression, timeZone);
53+
public CronTrigger(String expression, TimeZone timeZone) {
54+
this.sequenceGenerator = new CronSequenceGenerator(expression, timeZone);
55+
}
56+
57+
58+
/**
59+
* Return the cron pattern that this trigger has been built with.
60+
*/
61+
public String getExpression() {
62+
return this.sequenceGenerator.getExpression();
5563
}
5664

5765

@@ -78,14 +86,11 @@ public Date nextExecutionTime(TriggerContext triggerContext) {
7886
return this.sequenceGenerator.next(date);
7987
}
8088

81-
public String getExpression() {
82-
return this.sequenceGenerator.getExpression();
83-
}
8489

8590
@Override
86-
public boolean equals(Object obj) {
87-
return (this == obj || (obj instanceof CronTrigger &&
88-
this.sequenceGenerator.equals(((CronTrigger) obj).sequenceGenerator)));
91+
public boolean equals(Object other) {
92+
return (this == other || (other instanceof CronTrigger &&
93+
this.sequenceGenerator.equals(((CronTrigger) other).sequenceGenerator)));
8994
}
9095

9196
@Override

spring-context/src/test/java/org/springframework/scheduling/support/CronSequenceGeneratorTests.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -45,4 +45,14 @@ public void testAt0Minutes() {
4545
new CronSequenceGenerator("0 */2 1-4 * * *").next(new Date(2012, 6, 1, 9, 0)));
4646
}
4747

48+
@Test(expected = IllegalArgumentException.class)
49+
public void testWith0Increment() {
50+
new CronSequenceGenerator("*/0 * * * * *").next(new Date(2012, 6, 1, 9, 0));
51+
}
52+
53+
@Test(expected = IllegalArgumentException.class)
54+
public void testWithNegativeIncrement() {
55+
new CronSequenceGenerator("*/-1 * * * * *").next(new Date(2012, 6, 1, 9, 0));
56+
}
57+
4858
}

0 commit comments

Comments
 (0)