This commit is contained in:
Looly 2025-09-05 17:23:06 +08:00
parent 175dd746ac
commit b6e7287287
9 changed files with 79 additions and 28 deletions

View File

@ -97,7 +97,12 @@ public class AnnotationUtil {
// region ----- getAnnotation // region ----- getAnnotation
/** /**
* 获取直接声明的注解若已有缓存则从缓存中获取 * 获取直接声明的注解若已有缓存则从缓存中获取主要为
* <ul>
* <li>只返回直接声明在该元素上的注解</li>
* <li>不包括从父类或接口继承来的注解</li>
* <li>只获取当前类/方法/字段等自身定义的注解</li>
* </ul>
* *
* @param element {@link AnnotatedElement} * @param element {@link AnnotatedElement}
* @return 注解 * @return 注解
@ -108,7 +113,12 @@ public class AnnotationUtil {
} }
/** /**
* 获取指定注解 * 获取指定注解主要为:
* <ul>
* <li>返回该元素上的所有注解</li>
* <li>包括从父类或接口继承来的注解</li>
* <li>获取当前元素以及继承自父类或接口的所有注解</li>
* </ul>
* *
* @param annotationEle {@link AnnotatedElement}可以是ClassMethodFieldConstructorReflectPermission * @param annotationEle {@link AnnotatedElement}可以是ClassMethodFieldConstructorReflectPermission
* @param isToCombination 是否为转换为组合注解组合注解可以递归获取注解的注解 * @param isToCombination 是否为转换为组合注解组合注解可以递归获取注解的注解

View File

@ -342,8 +342,7 @@ public class HierarchicalAnnotatedElements implements AnnotatedElement, Iterable
scanHierarchy(mappings, (Class<?>)source, false, source); scanHierarchy(mappings, (Class<?>)source, false, source);
} }
// 原始元素是方法 // 原始元素是方法
else if (source instanceof Method) { else if (source instanceof final Method methodSource) {
final Method methodSource = (Method)source;
// 静态私有与被final关键字修饰方法无法被子类重写因此不可能具有层级结构 // 静态私有与被final关键字修饰方法无法被子类重写因此不可能具有层级结构
if (Modifier.isPrivate(methodSource.getModifiers()) if (Modifier.isPrivate(methodSource.getModifiers())
|| Modifier.isFinal(methodSource.getModifiers()) || Modifier.isFinal(methodSource.getModifiers())

View File

@ -276,14 +276,14 @@ public enum Month {
/** /**
* 获得指定月的最后一天 * 获得指定月的最后一天
* *
* @param month 月份从0开始 * @param monthBase0 月份从0开始
* @param isLeapYear 是否为闰年闰年只对二月有影响 * @param isLeapYear 是否为闰年闰年只对二月有影响
* @return 最后一天可能为28,29,30,31 * @return 最后一天可能为28,29,30,31
* @since 5.4.7 * @since 5.4.7
*/ */
public static int getLastDay(final int month, final boolean isLeapYear) { public static int getLastDay(final int monthBase0, final boolean isLeapYear) {
final Month of = of(month); final Month of = of(monthBase0);
Assert.notNull(of, "Invalid Month base 0: " + month); Assert.notNull(of, "Invalid Month base 0: " + monthBase0);
return of.getLastDay(isLeapYear); return of.getLastDay(isLeapYear);
} }

View File

@ -18,6 +18,7 @@ package cn.hutool.v7.cron.pattern;
import cn.hutool.v7.core.comparator.CompareUtil; import cn.hutool.v7.core.comparator.CompareUtil;
import cn.hutool.v7.core.date.CalendarUtil; import cn.hutool.v7.core.date.CalendarUtil;
import cn.hutool.v7.core.lang.Console;
import cn.hutool.v7.cron.pattern.matcher.PatternMatcher; import cn.hutool.v7.cron.pattern.matcher.PatternMatcher;
import cn.hutool.v7.cron.pattern.parser.PatternParser; import cn.hutool.v7.cron.pattern.parser.PatternParser;

View File

@ -40,7 +40,7 @@ public class DayOfMonthMatcher extends BoolArrayMatcher {
/** /**
* 给定的日期是否匹配当前匹配器 * 给定的日期是否匹配当前匹配器
* *
* @param value 被检查的值此处为日 * @param value 被检查的值此处为日从1开始
* @param month 实际的月份从1开始 * @param month 实际的月份从1开始
* @param isLeapYear 是否闰年 * @param isLeapYear 是否闰年
* @return 是否匹配 * @return 是否匹配

View File

@ -17,10 +17,10 @@
package cn.hutool.v7.cron.pattern.matcher; package cn.hutool.v7.cron.pattern.matcher;
import cn.hutool.v7.core.date.DateUtil; import cn.hutool.v7.core.date.DateUtil;
import cn.hutool.v7.core.text.StrUtil;
import cn.hutool.v7.cron.pattern.Part; import cn.hutool.v7.cron.pattern.Part;
import java.time.Year; import java.time.Year;
import java.util.Arrays;
import java.util.Calendar; import java.util.Calendar;
import java.util.TimeZone; import java.util.TimeZone;
@ -177,9 +177,15 @@ public class PatternMatcher {
@Override @Override
public String toString() { public String toString() {
return "PatternMatcher{" + return StrUtil.format("""
"matchers=" + Arrays.toString(matchers) + SECOND : {}
'}'; MINUTE : {}
HOUR : {}
DAY_OF_MONTH: {}
MONTH : {}
DAY_OF_WEEK : {}
YEAR : {}
""", (Object[]) this.matchers);
} }
/** /**

View File

@ -29,6 +29,11 @@ public class YearValueMatcher implements PartMatcher {
private final LinkedHashSet<Integer> valueList; private final LinkedHashSet<Integer> valueList;
/**
* 构造
*
* @param intValueList 年数字列表
*/
public YearValueMatcher(final Collection<Integer> intValueList) { public YearValueMatcher(final Collection<Integer> intValueList) {
this.valueList = new LinkedHashSet<>(intValueList); this.valueList = new LinkedHashSet<>(intValueList);
} }
@ -49,4 +54,11 @@ public class YearValueMatcher implements PartMatcher {
// 年无效此表达式整体无效 // 年无效此表达式整体无效
return -1; return -1;
} }
@Override
public String toString() {
return "YearValueMatcher{" +
"valueList=" + valueList +
'}';
}
} }

View File

@ -91,14 +91,11 @@ public class PartParser {
throw new CronException("Invalid part value: [{}]", value); throw new CronException("Invalid part value: [{}]", value);
} }
switch (this.part) { return switch (this.part) {
case DAY_OF_MONTH: case DAY_OF_MONTH -> new DayOfMonthMatcher(values);
return new DayOfMonthMatcher(values); case YEAR -> new YearValueMatcher(values);
case YEAR: default -> new BoolArrayMatcher(values);
return new YearValueMatcher(values); };
default:
return new BoolArrayMatcher(values);
}
} }
/** /**
@ -163,6 +160,7 @@ public class PartParser {
* <li>8-3</li> * <li>8-3</li>
* <li>3-3</li> * <li>3-3</li>
* </ul> * </ul>
* 其中"*"解析时按照min值处理
* *
* @param value 范围表达式 * @param value 范围表达式
* @param step 步进 * @param step 步进
@ -287,15 +285,15 @@ public class PartParser {
return part.getMax(); return part.getMax();
} }
switch (this.part) { return switch (this.part) {
case MONTH: case MONTH ->
// 月份从1开始 // 月份从1开始
return Month.of(name).getValueBaseOne(); Month.of(name).getValueBaseOne();
case DAY_OF_WEEK: case DAY_OF_WEEK ->
// 周从0开始0表示周日 // 周从0开始0表示周日
return Week.of(name).ordinal(); Week.of(name).ordinal();
} default -> throw new CronException("Invalid alias value: [{}]", name);
};
throw new CronException("Invalid alias value: [{}]", name);
} }
} }

View File

@ -16,6 +16,7 @@
package cn.hutool.v7.cron.pattern; package cn.hutool.v7.cron.pattern;
import cn.hutool.v7.core.date.DateTime;
import cn.hutool.v7.core.date.DateUtil; import cn.hutool.v7.core.date.DateUtil;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -60,4 +61,28 @@ public class CronPatternUtilTest {
Assertions.assertEquals("2018-10-31 03:00:00", matchedDates.get(3).toString()); Assertions.assertEquals("2018-10-31 03:00:00", matchedDates.get(3).toString());
Assertions.assertEquals("2018-10-31 04:00:00", matchedDates.get(4).toString()); Assertions.assertEquals("2018-10-31 04:00:00", matchedDates.get(4).toString());
} }
@Test
public void issue4056Test() {
// "*/5""1/5"意义相同从1号开始每5天一个匹配则匹配的天为
// 2025-02-01, 2025-02-06, 2025-02-11, 2025-02-16, 2025-02-21, 2025-02-26
// 2025-02-28不应该在匹配之列
final String cron = "0 0 0 */5 * ? *";
final CronPattern cronPattern = new CronPattern(cron);
final boolean match = cronPattern.match(DateUtil.parse("2025-02-28 00:00:00").toCalendar(), true);
Assertions.assertFalse( match);
}
@Test
public void issue4056Test2() {
final String cron = "0 0 0 */5 * ? *";
final CronPattern cronPattern = new CronPattern(cron);
final DateTime judgeTime = DateUtil.parse("2025-02-27 23:59:59");
final Date nextDate = CronPatternUtil.nextDateAfter(cronPattern, judgeTime);
// "*/5""1/5"意义相同从1号开始每5天一个匹配则匹配的天为
// 2025-02-01, 2025-02-06, 2025-02-11, 2025-02-16, 2025-02-21, 2025-02-26
// 下一个匹配日期应为2025-03-01
Assertions.assertEquals("2025-03-01 00:00:00", nextDate.toString());
}
} }