1

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'
4
  • trying out the code shared with jdoodle.com/execute-groovy-online seems to be working fine without the exception that you have mentioned. Commented Aug 28, 2024 at 2:02
  • That seems to imply that the problem may be outside of the code itself. How does the Groovy compiler access its available functions? What is helping it decide that getAt(String) is available but getAt(int) isn't? Commented Aug 28, 2024 at 15:28
  • 1
    You shouldn’t use this legacy class in the first place. A java.util.Date is, despite its name, actually an instant and getting its ‘day of month’ actually bears a time-zone specific conversion. If you use a LocalDate you can simply call getDayOfMonth(). If you have to interoperate with legacy code, you can convert a Date to a LocalDate using LocalDate.ofInstant(date.toInstant(), ZoneId.systemDefault()) (which indicates the time zone dependency that is otherwise hidden). Commented Aug 29, 2024 at 10:39
  • 1
    That's a good observation, and unfortunately the scope of my work right now is in cross-functional upgrades across a lot of different systems. I've had to set the boundary for myself to not waste time or energy rewriting good-enough code in other people's apps, no matter how much I sometimes want to. That's part of why I wanted to restore the previous code's functionality, rather than using one of the code fixes I came up with while researching. It's admittedly a patch job, but I don't know the history of these apps like their owners do. Why am I doing their upgrades then? Good question. Commented Aug 29, 2024 at 15:29

1 Answer 1

2

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!

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.