11/*
2- * Copyright 2002-2021 the original author or authors.
2+ * Copyright 2002-2024 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.
2929
3030/**
3131 * Extension of {@link CronField} for
32- * <a href="https://www.quartz-scheduler.org>Quartz</a> -specific fields.
32+ * <a href="https://www.quartz-scheduler.org" >Quartz</a>-specific fields.
3333 * Created using the {@code parse*} methods, uses a {@link TemporalAdjuster}
3434 * internally.
3535 *
36+ * <p>Supports a Quartz day-of-month/week field with an L/# expression. Follows
37+ * common cron conventions in every other respect, including 0-6 for SUN-SAT
38+ * (plus 7 for SUN as well). Note that Quartz deviates from the day-of-week
39+ * convention in cron through 1-7 for SUN-SAT whereas Spring strictly follows
40+ * cron even in combination with the optional Quartz-specific L/# expressions.
41+ *
3642 * @author Arjen Poutsma
3743 * @since 5.3
3844 */
@@ -60,8 +66,9 @@ private QuartzCronField(Type type, Type rollForwardType, TemporalAdjuster adjust
6066 this .rollForwardType = rollForwardType ;
6167 }
6268
69+
6370 /**
64- * Returns whether the given value is a Quartz day-of-month field.
71+ * Determine whether the given value is a Quartz day-of-month field.
6572 */
6673 public static boolean isQuartzDaysOfMonthField (String value ) {
6774 return value .contains ("L" ) || value .contains ("W" );
@@ -78,14 +85,14 @@ public static QuartzCronField parseDaysOfMonth(String value) {
7885 if (idx != 0 ) {
7986 throw new IllegalArgumentException ("Unrecognized characters before 'L' in '" + value + "'" );
8087 }
81- else if (value .length () == 2 && value .charAt (1 ) == 'W' ) { // "LW"
88+ else if (value .length () == 2 && value .charAt (1 ) == 'W' ) { // "LW"
8289 adjuster = lastWeekdayOfMonth ();
8390 }
8491 else {
85- if (value .length () == 1 ) { // "L"
92+ if (value .length () == 1 ) { // "L"
8693 adjuster = lastDayOfMonth ();
8794 }
88- else { // "L-[0-9]+"
95+ else { // "L-[0-9]+"
8996 int offset = Integer .parseInt (value .substring (idx + 1 ));
9097 if (offset >= 0 ) {
9198 throw new IllegalArgumentException ("Offset '" + offset + " should be < 0 '" + value + "'" );
@@ -103,7 +110,7 @@ else if (value.length() == 2 && value.charAt(1) == 'W') { // "LW"
103110 else if (idx != value .length () - 1 ) {
104111 throw new IllegalArgumentException ("Unrecognized characters after 'W' in '" + value + "'" );
105112 }
106- else { // "[0-9]+W"
113+ else { // "[0-9]+W"
107114 int dayOfMonth = Integer .parseInt (value .substring (0 , idx ));
108115 dayOfMonth = Type .DAY_OF_MONTH .checkValidValue (dayOfMonth );
109116 TemporalAdjuster adjuster = weekdayNearestTo (dayOfMonth );
@@ -114,15 +121,16 @@ else if (idx != value.length() - 1) {
114121 }
115122
116123 /**
117- * Returns whether the given value is a Quartz day-of-week field.
124+ * Determine whether the given value is a Quartz day-of-week field.
118125 */
119126 public static boolean isQuartzDaysOfWeekField (String value ) {
120127 return value .contains ("L" ) || value .contains ("#" );
121128 }
122129
123130 /**
124- * Parse the given value into a days of week {@code QuartzCronField}, the sixth entry of a cron expression.
125- * Expects a "L" or "#" in the given value.
131+ * Parse the given value into a days of week {@code QuartzCronField},
132+ * the sixth entry of a cron expression.
133+ * <p>Expects a "L" or "#" in the given value.
126134 */
127135 public static QuartzCronField parseDaysOfWeek (String value ) {
128136 int idx = value .lastIndexOf ('L' );
@@ -135,7 +143,7 @@ public static QuartzCronField parseDaysOfWeek(String value) {
135143 if (idx == 0 ) {
136144 throw new IllegalArgumentException ("No day-of-week before 'L' in '" + value + "'" );
137145 }
138- else { // "[0-7]L"
146+ else { // "[0-7]L"
139147 DayOfWeek dayOfWeek = parseDayOfWeek (value .substring (0 , idx ));
140148 adjuster = lastInMonth (dayOfWeek );
141149 }
@@ -157,7 +165,6 @@ else if (idx == value.length() - 1) {
157165 throw new IllegalArgumentException ("Ordinal '" + ordinal + "' in '" + value +
158166 "' must be positive number " );
159167 }
160-
161168 TemporalAdjuster adjuster = dayOfWeekInMonth (ordinal , dayOfWeek );
162169 return new QuartzCronField (Type .DAY_OF_WEEK , Type .DAY_OF_MONTH , adjuster , value );
163170 }
@@ -167,14 +174,13 @@ else if (idx == value.length() - 1) {
167174 private static DayOfWeek parseDayOfWeek (String value ) {
168175 int dayOfWeek = Integer .parseInt (value );
169176 if (dayOfWeek == 0 ) {
170- dayOfWeek = 7 ; // cron is 0 based; java.time 1 based
177+ dayOfWeek = 7 ; // cron is 0 based; java.time 1 based
171178 }
172179 try {
173180 return DayOfWeek .of (dayOfWeek );
174181 }
175182 catch (DateTimeException ex ) {
176- String msg = ex .getMessage () + " '" + value + "'" ;
177- throw new IllegalArgumentException (msg , ex );
183+ throw new IllegalArgumentException (ex .getMessage () + " '" + value + "'" , ex );
178184 }
179185 }
180186
@@ -213,10 +219,10 @@ private static TemporalAdjuster lastWeekdayOfMonth() {
213219 Temporal lastDom = adjuster .adjustInto (temporal );
214220 Temporal result ;
215221 int dow = lastDom .get (ChronoField .DAY_OF_WEEK );
216- if (dow == 6 ) { // Saturday
222+ if (dow == 6 ) { // Saturday
217223 result = lastDom .minus (1 , ChronoUnit .DAYS );
218224 }
219- else if (dow == 7 ) { // Sunday
225+ else if (dow == 7 ) { // Sunday
220226 result = lastDom .minus (2 , ChronoUnit .DAYS );
221227 }
222228 else {
@@ -227,7 +233,7 @@ else if (dow == 7) { // Sunday
227233 }
228234
229235 /**
230- * Return a temporal adjuster that finds the nth-to-last day of the month.
236+ * Returns a temporal adjuster that finds the nth-to-last day of the month.
231237 * @param offset the negative offset, i.e. -3 means third-to-last
232238 * @return a nth-to-last day-of-month adjuster
233239 */
@@ -241,7 +247,7 @@ private static TemporalAdjuster lastDayWithOffset(int offset) {
241247 }
242248
243249 /**
244- * Return a temporal adjuster that finds the weekday nearest to the given
250+ * Returns a temporal adjuster that finds the weekday nearest to the given
245251 * day-of-month. If {@code dayOfMonth} falls on a Saturday, the date is
246252 * moved back to Friday; if it falls on a Sunday (or if {@code dayOfMonth}
247253 * is 1 and it falls on a Saturday), it is moved forward to Monday.
@@ -253,10 +259,10 @@ private static TemporalAdjuster weekdayNearestTo(int dayOfMonth) {
253259 int current = Type .DAY_OF_MONTH .get (temporal );
254260 DayOfWeek dayOfWeek = DayOfWeek .from (temporal );
255261
256- if ((current == dayOfMonth && isWeekday (dayOfWeek )) || // dayOfMonth is a weekday
257- (dayOfWeek == DayOfWeek .FRIDAY && current == dayOfMonth - 1 ) || // dayOfMonth is a Saturday, so Friday before
258- (dayOfWeek == DayOfWeek .MONDAY && current == dayOfMonth + 1 ) || // dayOfMonth is a Sunday, so Monday after
259- (dayOfWeek == DayOfWeek .MONDAY && dayOfMonth == 1 && current == 3 )) { // dayOfMonth is Saturday 1st, so Monday 3rd
262+ if ((current == dayOfMonth && isWeekday (dayOfWeek )) || // dayOfMonth is a weekday
263+ (dayOfWeek == DayOfWeek .FRIDAY && current == dayOfMonth - 1 ) || // dayOfMonth is a Saturday, so Friday before
264+ (dayOfWeek == DayOfWeek .MONDAY && current == dayOfMonth + 1 ) || // dayOfMonth is a Sunday, so Monday after
265+ (dayOfWeek == DayOfWeek .MONDAY && dayOfMonth == 1 && current == 3 )) { // dayOfMonth is Saturday 1st, so Monday 3rd
260266 return temporal ;
261267 }
262268 int count = 0 ;
@@ -292,7 +298,7 @@ private static boolean isWeekday(DayOfWeek dayOfWeek) {
292298 }
293299
294300 /**
295- * Return a temporal adjuster that finds the last of the given doy -of-week
301+ * Returns a temporal adjuster that finds the last of the given day -of-week
296302 * in a month.
297303 */
298304 private static TemporalAdjuster lastInMonth (DayOfWeek dayOfWeek ) {
@@ -329,6 +335,7 @@ private static Temporal rollbackToMidnight(Temporal current, Temporal result) {
329335 }
330336 }
331337
338+
332339 @ Override
333340 public <T extends Temporal & Comparable <? super T >> T nextOrSame (T temporal ) {
334341 T result = adjust (temporal );
@@ -345,7 +352,6 @@ public <T extends Temporal & Comparable<? super T>> T nextOrSame(T temporal) {
345352 return result ;
346353 }
347354
348-
349355 @ Nullable
350356 @ SuppressWarnings ("unchecked" )
351357 private <T extends Temporal & Comparable <? super T >> T adjust (T temporal ) {
@@ -354,27 +360,25 @@ private <T extends Temporal & Comparable<? super T>> T adjust(T temporal) {
354360
355361
356362 @ Override
357- public int hashCode () {
358- return this .value .hashCode ();
359- }
360-
361- @ Override
362- public boolean equals (Object o ) {
363- if (this == o ) {
363+ public boolean equals (@ Nullable Object other ) {
364+ if (this == other ) {
364365 return true ;
365366 }
366- if (!(o instanceof QuartzCronField )) {
367+ if (!(other instanceof QuartzCronField )) {
367368 return false ;
368369 }
369- QuartzCronField other = (QuartzCronField ) o ;
370- return type () == other .type () &&
371- this .value .equals (other .value );
370+ QuartzCronField otherField = (QuartzCronField ) other ;
371+ return (type () == otherField .type () && this .value .equals (otherField .value ));
372+ }
373+
374+ @ Override
375+ public int hashCode () {
376+ return this .value .hashCode ();
372377 }
373378
374379 @ Override
375380 public String toString () {
376381 return type () + " '" + this .value + "'" ;
377-
378382 }
379383
380384}
0 commit comments