Groovy, the programming language based on JVM implements a feature called Categories. It is originally borrowed from Objective-C . Simple explanation for this feature can be the ability to implement new methods in existing classes without modifying their original code which in some way is injecting new methods through a Category class. For more information official documentation can be found here .
Rather interesting for me was playing with the TimeCategory class for writing a short and easy script for fixing some datetime columns in database. This class offers a convenient way of Date and Time manipulation.
General syntax for categories is the following:
use ( Class ) { // Some code }
Concrete usage of TimeCategory:
use ( TimeCategory ) { // application on numbers: println 1.minute.from.now println 10.hours.ago // application on dates def someDate = new Date() println someDate - 3.months }
Seems weird? From when Integer has months, minutes, hours etc. methods ? Well it still doesn’t have any of that, however those methods are dynamically added with the TimeCategory use.
If you are interested how is this possible I suggest you to go through TimeCategory API and source code if possible. Also this forum post can be useful for deeper understanding of the groovy magic.
And last but not least, an example groovy script for your pleasure.
@GrabConfig(systemClassLoader=true) @Grab(group='mysql', module='mysql-connector-java', version='5.1.27') import groovy.time.TimeCategory import java.sql.Timestamp sql = groovy.sql.Sql.newInstance( "jdbc:mysql://hostname:3306/DB_name?autoReconnect=true", "user", "password", "com.mysql.jdbc.Driver") def rows= [:] // Select Data sql.eachRow("select * from Table_Name"){ def impDates = new ImportedDates() // This is some custom Class found in the same package/directory if script impDates.dateColumn = it.dateColumn if(impDates.dateColumn!=null){ use(TimeCategory){ impDates.dateColumn = impDates.dateColumn - 1.day // Shift dateColumn for one day backwards in time } } rows.put(it.UID,impDates) // Put private key and ImportedDate object in Map } // Update Data rows.each {row-> ImportedDates id = row.value // Check if value is different from null, if it is convert it to Timestamp(we use datetime column in db) and execute update query dateColumn = null if(id.dateColumn) dateColumn = new Timestamp(id.dateColumn.getTime()) // Actual update query sql.executeUpdate('update Table_Name set dateColumn = ? ' + 'where UID like ?', [dateColumn, row.key.toString()]) }
Cheers.