I am upgrading a groovy app from JDK11 to JDK17. One error I had to debug was with the following code:
public static def getDayFromDate (Date date) {
return date[Calendar.DAY_OF_MONTH]
}
For those unfamiliar, in groovy, you can use the [] accessor as a stand-in for the groovy getAt(int) function, so the above line is synonymous with return date.getAt(Calendar.DAY_OF_MONTH). I mention this just so I can refer to the getAt function without introducing a name out of nowhere.
getAt(), in the context of java.util.Date, saves you from having to write the below:
public static def getDayFromDate (Date date) {
Calendar calendar = Calendar.getInstance()
calendar.setTime(date)
return calendar.get(Calendar.DAY_OF_MONTH)
}
And Calendar.DAY_OF_MONTH is just a built-in java.util.Calendar enumerator that equates to the int 5.
Nothing complicated so far.
Well after upgrading to Java 17 and Groovy 4.0, my line of code started complaining.
groovy.lang.MissingMethodException: No signature of method: java.util.Date.getAt() is applicable for argument types: (Integer) values: [5]
So I checked it out, and sure enough, I found that getAt is now expecting a String parameter instead of an int.
Ultimately, the working code is now
public static def getDayFromDate (Date date) {
return date["date"]
}
So now it seems it's using the Object class's getAt(String) to retrieve the property via mapping, instead of java.util.Date's getAt(int) which short circuits the Calendar code.
(For reference, using the 3-line Calendar code above works perfectly, but I kept digging because I wanted to understand why getAt wasn't working).
I suspected this might also be an IntelliJ problem, so I ran my tests via the terminal too. getAt(Calendar.DAY_OF_MONTH) fails. getAt("date") works. IntelliJ doesn't seem to have anything to do with it.
I'm glad to have working code, but it's really bothering me that I don't understand why or how it's changed. I'd much prefer to stick with the enumerated value if possible.
My gradle groovy import has changed from
implementation 'org.codehaus.groovy:groovy-all:2.4.15'
to
implementation 'org.apache.groovy:groovy-all:4.0.20'
java.util.Dateis, despite its name, actually an instant and getting its ‘day of month’ actually bears a time-zone specific conversion. If you use aLocalDateyou can simply callgetDayOfMonth(). If you have to interoperate with legacy code, you can convert aDateto aLocalDateusingLocalDate.ofInstant(date.toInstant(), ZoneId.systemDefault())(which indicates the time zone dependency that is otherwise hidden).