Thursday, May 19, 2011

Groovy vs Java difference provides a WTF moment

We all (should) know that not ALL Java is valid Groovy, but if you don't spend you day working in Groovy, then sometimes you forget these differences.   These 'gotchas' are documented here but who reads this stuff, right?  :-)

I wanted to get DatabaseMetadata for a database, specifically a list of table names, so I started with a copy of Java code that already did the same thing.

Class.forName(jdbcDriver);
Connection con = DriverManager.getConnection(jdbcURL, "root", "root");
DatabaseMetaData dbmd = con.getMetaData();
String[] tableTypes = { "TABLE" };
ResultSet allTables = dbmd.getTables(null, null, null, tableTypes);
System.out.println("processing tables...");
while (allTables.next()) {
    String table_name = allTables.getString("TABLE_NAME");
    System.out.println("processing table"+table_name);
}

Should be simple, right - drop the semi-colons and look for other opportunities to shorten the code using Groovy.

def db = Sql.newInstance('jdbc:mysql://127.0.0.1:3306/mydb', 'root', 'root', 'com.mysql.jdbc.Driver')
def metaData = db.getConnection().getMetaData()
println("Driver Name: " + metaData.getDriverName())
println("Database Product: " + metaData.getDatabaseProductName())
println("Driver Name: "+ metaData.getDriverName())
println("Driver Version: "+ metaData.getDriverVersion())
String[] tableTypes = { "TABLE" }
ResultSet allTables = metaData.getTables(null, null, null, tableTypes)
while (allTables.next()) {
    String table_name = allTables.getString("TABLE_NAME")
    println "processing table "+table_name
}

And it almost worked!   The thing that threw me was that not only does the code compile, but it also returns correct values for some of the methods in the DatabaseMetadata, but when it came time to iterate across the table names, there were none.  Come on, I just ran almost the exact code in Java and it spit out all the table names in my database.  What the heck did I mess up this time?

My error was the 3rd bullet on the list of gotchas from above - how NOT to initialize an array in Groovy...

String[] tableTypesJava = { "TABLE" }
String[] tableTypesGroovy = [ "TABLE" ]
println tableTypesJava.class
println tableTypesGroovy.class
assertEquals(tableTypesGroovy, tableTypesJava)  // this will fail!

Both variables say they are String[] but tableTypesJava is really closure when compiled in Groovy! The fix to the Groovy code is to use the brackets when initializing the array and not the braces - basically the tableTypesGroovy from above. Guess it's time to RTFM...

Hope this helps!