CronSequenceGenerator.isValidExpression actually validates cron fields

Issue: SPR-15604
This commit is contained in:
Juergen Hoeller 2017-06-30 01:54:32 +02:00
parent cc74a2891a
commit 5f4d1a4628
2 changed files with 44 additions and 10 deletions

View File

@ -17,7 +17,6 @@
package org.springframework.scheduling.support; package org.springframework.scheduling.support;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet; import java.util.BitSet;
import java.util.Calendar; import java.util.Calendar;
import java.util.Collections; import java.util.Collections;
@ -26,6 +25,7 @@ import java.util.GregorianCalendar;
import java.util.List; import java.util.List;
import java.util.TimeZone; import java.util.TimeZone;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
@ -50,6 +50,7 @@ import org.springframework.util.StringUtils;
* *
* @author Dave Syer * @author Dave Syer
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Ruslan Sibgatullin
* @since 3.0 * @since 3.0
* @see CronTrigger * @see CronTrigger
*/ */
@ -57,6 +58,7 @@ public class CronSequenceGenerator {
private final String expression; private final String expression;
@Nullable
private final TimeZone timeZone; private final TimeZone timeZone;
private final BitSet months = new BitSet(12); private final BitSet months = new BitSet(12);
@ -96,6 +98,12 @@ public class CronSequenceGenerator {
parse(expression); parse(expression);
} }
private CronSequenceGenerator(String expression, String[] fields) {
this.expression = expression;
this.timeZone = null;
doParse(fields);
}
/** /**
* Return the cron pattern that this sequence generator has been built for. * Return the cron pattern that this sequence generator has been built for.
@ -234,7 +242,7 @@ public class CronSequenceGenerator {
// roll over if needed // roll over if needed
if (nextValue == -1) { if (nextValue == -1) {
calendar.add(nextField, 1); calendar.add(nextField, 1);
reset(calendar, Arrays.asList(field)); reset(calendar, Collections.singletonList(field));
nextValue = bits.nextSetBit(0); nextValue = bits.nextSetBit(0);
} }
if (nextValue != value) { if (nextValue != value) {
@ -265,12 +273,17 @@ public class CronSequenceGenerator {
throw new IllegalArgumentException(String.format( throw new IllegalArgumentException(String.format(
"Cron expression must consist of 6 fields (found %d in \"%s\")", fields.length, expression)); "Cron expression must consist of 6 fields (found %d in \"%s\")", fields.length, expression));
} }
doParse(fields);
}
private void doParse(String[] fields) {
setNumberHits(this.seconds, fields[0], 0, 60); setNumberHits(this.seconds, fields[0], 0, 60);
setNumberHits(this.minutes, fields[1], 0, 60); setNumberHits(this.minutes, fields[1], 0, 60);
setNumberHits(this.hours, fields[2], 0, 24); setNumberHits(this.hours, fields[2], 0, 24);
setDaysOfMonth(this.daysOfMonth, fields[3]); setDaysOfMonth(this.daysOfMonth, fields[3]);
setMonths(this.months, fields[4]); setMonths(this.months, fields[4]);
setDays(this.daysOfWeek, replaceOrdinals(fields[5], "SUN,MON,TUE,WED,THU,FRI,SAT"), 8); setDays(this.daysOfWeek, replaceOrdinals(fields[5], "SUN,MON,TUE,WED,THU,FRI,SAT"), 8);
if (this.daysOfWeek.get(7)) { if (this.daysOfWeek.get(7)) {
// Sunday can be represented as 0 or 7 // Sunday can be represented as 0 or 7
this.daysOfWeek.set(0); this.daysOfWeek.set(0);
@ -388,19 +401,29 @@ public class CronSequenceGenerator {
/** /**
* Determine whether the specified expression represents a valid cron pattern. * Determine whether the specified expression represents a valid cron pattern.
* <p>Specifically, this method verifies that the expression contains six
* fields separated by single spaces.
* @param expression the expression to evaluate * @param expression the expression to evaluate
* @return {@code true} if the given expression is a valid cron expression * @return {@code true} if the given expression is a valid cron expression
* @since 4.3 * @since 4.3
*/ */
public static boolean isValidExpression(String expression) { public static boolean isValidExpression(@Nullable String expression) {
if (expression == null) {
return false;
}
String[] fields = StringUtils.tokenizeToStringArray(expression, " "); String[] fields = StringUtils.tokenizeToStringArray(expression, " ");
return areValidCronFields(fields); if (!areValidCronFields(fields)) {
return false;
}
try {
new CronSequenceGenerator(expression, fields);
return true;
}
catch (IllegalArgumentException ex) {
return false;
}
} }
private static boolean areValidCronFields(String[] fields) { private static boolean areValidCronFields(@Nullable String[] fields) {
return (fields.length == 6); return (fields != null && fields.length == 6);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2016 the original author or authors. * Copyright 2002-2017 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -24,6 +24,7 @@ import static org.junit.Assert.*;
/** /**
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Ruslan Sibgatullin
*/ */
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public class CronSequenceGeneratorTests { public class CronSequenceGeneratorTests {
@ -82,10 +83,20 @@ public class CronSequenceGeneratorTests {
} }
@Test @Test
public void invalidExpression() { public void invalidExpressionWithLength() {
assertFalse(CronSequenceGenerator.isValidExpression("0 */2 1-4 * * * *")); assertFalse(CronSequenceGenerator.isValidExpression("0 */2 1-4 * * * *"));
} }
@Test
public void invalidExpressionWithSeconds() {
assertFalse(CronSequenceGenerator.isValidExpression("100 */2 1-4 * * *"));
}
@Test
public void invalidExpressionWithMonths() {
assertFalse(CronSequenceGenerator.isValidExpression("0 */2 1-4 * INVALID *"));
}
@Test @Test
public void nullExpression() { public void nullExpression() {
assertFalse(CronSequenceGenerator.isValidExpression(null)); assertFalse(CronSequenceGenerator.isValidExpression(null));