Skip to content

Commit 5f4d1a4

Browse files
committed
CronSequenceGenerator.isValidExpression actually validates cron fields
Issue: SPR-15604
1 parent cc74a28 commit 5f4d1a4

File tree

2 files changed

+44
-10
lines changed

2 files changed

+44
-10
lines changed

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

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package org.springframework.scheduling.support;
1818

1919
import java.util.ArrayList;
20-
import java.util.Arrays;
2120
import java.util.BitSet;
2221
import java.util.Calendar;
2322
import java.util.Collections;
@@ -26,6 +25,7 @@
2625
import java.util.List;
2726
import java.util.TimeZone;
2827

28+
import org.springframework.lang.Nullable;
2929
import org.springframework.util.StringUtils;
3030

3131
/**
@@ -50,13 +50,15 @@
5050
*
5151
* @author Dave Syer
5252
* @author Juergen Hoeller
53+
* @author Ruslan Sibgatullin
5354
* @since 3.0
5455
* @see CronTrigger
5556
*/
5657
public class CronSequenceGenerator {
5758

5859
private final String expression;
5960

61+
@Nullable
6062
private final TimeZone timeZone;
6163

6264
private final BitSet months = new BitSet(12);
@@ -96,6 +98,12 @@ public CronSequenceGenerator(String expression, TimeZone timeZone) {
9698
parse(expression);
9799
}
98100

101+
private CronSequenceGenerator(String expression, String[] fields) {
102+
this.expression = expression;
103+
this.timeZone = null;
104+
doParse(fields);
105+
}
106+
99107

100108
/**
101109
* Return the cron pattern that this sequence generator has been built for.
@@ -234,7 +242,7 @@ private int findNext(BitSet bits, int value, Calendar calendar, int field, int n
234242
// roll over if needed
235243
if (nextValue == -1) {
236244
calendar.add(nextField, 1);
237-
reset(calendar, Arrays.asList(field));
245+
reset(calendar, Collections.singletonList(field));
238246
nextValue = bits.nextSetBit(0);
239247
}
240248
if (nextValue != value) {
@@ -265,12 +273,17 @@ private void parse(String expression) throws IllegalArgumentException {
265273
throw new IllegalArgumentException(String.format(
266274
"Cron expression must consist of 6 fields (found %d in \"%s\")", fields.length, expression));
267275
}
276+
doParse(fields);
277+
}
278+
279+
private void doParse(String[] fields) {
268280
setNumberHits(this.seconds, fields[0], 0, 60);
269281
setNumberHits(this.minutes, fields[1], 0, 60);
270282
setNumberHits(this.hours, fields[2], 0, 24);
271283
setDaysOfMonth(this.daysOfMonth, fields[3]);
272284
setMonths(this.months, fields[4]);
273285
setDays(this.daysOfWeek, replaceOrdinals(fields[5], "SUN,MON,TUE,WED,THU,FRI,SAT"), 8);
286+
274287
if (this.daysOfWeek.get(7)) {
275288
// Sunday can be represented as 0 or 7
276289
this.daysOfWeek.set(0);
@@ -388,19 +401,29 @@ private int[] getRange(String field, int min, int max) {
388401

389402
/**
390403
* Determine whether the specified expression represents a valid cron pattern.
391-
* <p>Specifically, this method verifies that the expression contains six
392-
* fields separated by single spaces.
393404
* @param expression the expression to evaluate
394405
* @return {@code true} if the given expression is a valid cron expression
395406
* @since 4.3
396407
*/
397-
public static boolean isValidExpression(String expression) {
408+
public static boolean isValidExpression(@Nullable String expression) {
409+
if (expression == null) {
410+
return false;
411+
}
398412
String[] fields = StringUtils.tokenizeToStringArray(expression, " ");
399-
return areValidCronFields(fields);
413+
if (!areValidCronFields(fields)) {
414+
return false;
415+
}
416+
try {
417+
new CronSequenceGenerator(expression, fields);
418+
return true;
419+
}
420+
catch (IllegalArgumentException ex) {
421+
return false;
422+
}
400423
}
401424

402-
private static boolean areValidCronFields(String[] fields) {
403-
return (fields.length == 6);
425+
private static boolean areValidCronFields(@Nullable String[] fields) {
426+
return (fields != null && fields.length == 6);
404427
}
405428

406429

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

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2017 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.
@@ -24,6 +24,7 @@
2424

2525
/**
2626
* @author Juergen Hoeller
27+
* @author Ruslan Sibgatullin
2728
*/
2829
@SuppressWarnings("deprecation")
2930
public class CronSequenceGeneratorTests {
@@ -82,10 +83,20 @@ public void validExpression() {
8283
}
8384

8485
@Test
85-
public void invalidExpression() {
86+
public void invalidExpressionWithLength() {
8687
assertFalse(CronSequenceGenerator.isValidExpression("0 */2 1-4 * * * *"));
8788
}
8889

90+
@Test
91+
public void invalidExpressionWithSeconds() {
92+
assertFalse(CronSequenceGenerator.isValidExpression("100 */2 1-4 * * *"));
93+
}
94+
95+
@Test
96+
public void invalidExpressionWithMonths() {
97+
assertFalse(CronSequenceGenerator.isValidExpression("0 */2 1-4 * INVALID *"));
98+
}
99+
89100
@Test
90101
public void nullExpression() {
91102
assertFalse(CronSequenceGenerator.isValidExpression(null));

0 commit comments

Comments
 (0)