Search code examples
groovyjava-17java.util.date

Java 11 -> 17: Groovy now uses Object getAt(String) instead of java.util.Date getAt(int)


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'

Solution

  • Per this groovy changelog, Seems like the java.util.Date extensions were moved to a separate groovy-dateutil module after groovy 2.5. I was jumping from 2.4.15 to 4.0.20.

    Adding implementation "org.apache.groovy:groovy-dateutil:4.0.20" to my build.gradle restored the missing functionality!