You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JDK11升级至JDK17:Groovy中Date的getAt方法参数类型变更问题

Groovy4.0 + JDK17下java.util.Date.getAt(int)失效的原因及替代方案

问题背景

将Groovy应用从JDK11(Groovy 2.4.15)升级到JDK17(Groovy 4.0.20)后,原有通过Groovy下标访问器调用Date.getAt(int)获取日期天数的代码报错:

原有代码:

public static def getDayFromDate(Date date) {
  return date[Calendar.DAY_OF_MONTH]
}

报错信息:

groovy.lang.MissingMethodException: No signature of method: java.util.Date.getAt() is applicable for argument types: (Integer) values: [5]

发现Groovy4.0中Date.getAt()仅支持String参数(如date["date"]可获取天数),但希望继续使用Calendar枚举值的写法,并了解参数类型变更的原因。

原因分析

  1. Groovy归属变更与API适配调整:Groovy从Codehaus迁移到Apache后,Groovy4.x版本对JDK废弃API的处理逻辑做了大幅调整。java.util.Date在JDK11+中已有大量方法被标记为废弃,Groovy2.x为Date添加的getAt(int)扩展方法是基于Calendar的封装,但Groovy4.x为贴合JDK的废弃导向,移除了该int参数版本的扩展,转而提供更直观的String参数版本(如"year"、"month"、"date"等对应Calendar字段)。

  2. JDK17模块系统与反射限制:JDK17的模块系统对反射操作的限制更严格,Groovy2.x中Date.getAt(int)可能依赖反射调用Calendar的相关方法,而JDK17的权限控制导致这种实现方式不再可行,因此Groovy4.x选择了更安全的String参数方案。

替代方案

方案1:复用Calendar枚举值的传统写法

直接使用Calendar标准API,兼容性好:

public static def getDayFromDate(Date date) {
    def calendar = Calendar.getInstance()
    calendar.time = date
    return calendar.get(Calendar.DAY_OF_MONTH)
}

注意:Calendar不是线程安全的,多线程环境建议每次新建实例或使用ThreadLocal<Calendar>保证线程安全。

方案2:自定义扩展方法恢复原有写法

通过Groovy扩展机制为Date重新添加getAt(int)方法,继续使用Calendar枚举值:

  1. 创建扩展类:
package com.yourcompany.extensions

import java.util.Calendar
import java.util.Date

class DateExtension {
    static Object getAt(Date date, int calendarField) {
        def calendar = Calendar.getInstance()
        calendar.time = date
        return calendar.get(calendarField)
    }
}
  1. 注册扩展:在src/main/resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule文件中添加:
moduleName=custom-date-extension
moduleVersion=1.0
extensionClasses=com.yourcompany.extensions.DateExtension

完成后即可继续使用date[Calendar.DAY_OF_MONTH]的写法。

方案3:迁移到Java 8+日期API(推荐)

JDK17完全支持Java 8引入的java.time API,该API线程安全且设计更合理,建议替换旧的Date和Calendar:

import java.time.ZoneId

public static def getDayFromDate(Date date) {
    return date.toInstant()
               .atZone(ZoneId.systemDefault())
               .toLocalDate()
               .getDayOfMonth()
}

内容的提问来源于stack exchange,提问作者Reed M

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 04:18:16