Wednesday, October 24, 2012

List in groovy-wslite request

Groovy-wslite is currently recommended way for doing client calls to web services from groovy. It has very interesting format for describing requests, unfortunately it is not very well documented, and for me it was totally unclear how to send lists of objects to service. Fortunately, source code is available and is easy to dig if you have some time.
Basically, all you need to do is just send a bunch of regular objects, and they will be combined in list on the other end. There is example:

def response = client.send(SOAPAction:'https://server/services/service') {
  body {
    create() {
      dto {
        name('name123')
        id('123456')
        child {
              name('child1')
              birthday('2011-01-01')
            }
        child {
              name('child2')
              birthday('2012-01-01')
            }
      }
    }
  }
}


NullPointerException when saving Grails object

Recently I got very strange NPE while saving updated entity in Grails application:

java.lang.NullPointerException
 at com.test.MyController$_closure5.doCall(MyController.groovy:69)
 at com.test.MyController$_closure5.doCall(MyController.groovy)
 at net.bull.javamelody.JspWrapper.invoke(JspWrapper.java:149)
 at net.bull.javamelody.JdbcWrapper$DelegatingInvocationHandler.invoke(JdbcWrapper.java:259)
 at $Proxy49.forward(Unknown Source)
 at net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:206)
 at net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:179)
 at java.lang.Thread.run(Thread.java:662)

All I was doing on line 69 was just calling save() method, object obviously was not null, all fields and dependencies too. Even more - saving another object from same method was perfectly fine, but not one particular.
Finally, I got the reason - object had null in it's version field. Obviously migration was not done properly or it was manually created object in bad schema, but setting version solved my problem easily, but bad error reporting - didn't helped.

Thursday, October 4, 2012

Reusing methods from different hierarchies with Mixins

Grails application can be tested with many different tools: Geb, Selenium, Grails own integration testing framework, etc. To use them, you have to extend some basic test case class, like GebReportingSpec, GroovyTestCase, GrailsUnitTestCase.
Usually there is a lot of methods that are used from all these frameworks, for example for data initialization and manipulation outside of test scenario scope. So how it would be possible to reuse these methods without access to class hierarchy and avoid code duplication. One easy way is to use Groovy Mixins, that allow to add new methods to any class without affecting existing class hierarchy. For example:


@Mixin(GenericTestMethods)
class SpecificTests extends GroovyTestCase {
...


Monday, October 1, 2012

Groovy tricks: initializing map with array values by default

I feel a little Mr. Haki today, so will post Groovy recipe.
Very often, there is case when you want to aggregate some values by single key, but groupBy is not suitable or flexible enough. In this case, with every new key, you should initialize this new value with array, like:


Map values = [:]
[[key:'user1', val:123],[key:'user1', val:567],[key:'user2', val:999]].each {
  def var = values[it.key]
  if (!var) {
    var = []
    values[it.key] = var
  }
  var << it.val
}
println values

[user1:[123, 567], user2:[999]]

This is nice, but "if" statement looks redundant and ugly and complicates things. Fortunately, there is great Groovy method called "withDefault" which does pretty much same things, but in much groovier way: if there is no key, instead of null it assigns specified value to your key. So above example can be rewritten like:


Map values = [:].withDefault {k->[]}
[[key:'user1', val:123],[key:'user1', val:567],[key:'user2', val:999]].each {
  values[it.key] << it.val
}
println values
[user1:[123, 567], user2:[999]]