Gangmax Blog

自由之思想,独立之精神

Some Groovy Hints I Learned

| Comments

Variables are required to be declared in Class while not required in Script

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
groovy:000> class Callee {
groovy:001>   void hello() {
groovy:002>      String name = "world"
groovy:003>      println "hello, ${name}"
groovy:004>   }
groovy:005> }
===> true
groovy:000> callee = new Callee()
===> Callee@1b00667
groovy:000> callee.hello()
hello, world
===> null
groovy:000> class Callee {
groovy:001>   void hello() {
groovy:002>      def name = "world"
groovy:003>      println "hello, ${name}"
groovy:004>   }
groovy:005> }
===> true
groovy:000> callee = new Callee()
===> Callee@8938a8
groovy:000> callee.hello()
hello, world
===> null
groovy:000> class Callee {
groovy:001>   void hello() {
groovy:002>      name = "world"
groovy:003>      println "hello, ${name}"
groovy:004>   }
groovy:005> }
===> true
groovy:000> callee = new Callee()
===> Callee@16101eb
groovy:000> callee.hello()
ERROR groovy.lang.MissingPropertyException:
No such property: name for class: Callee
        at Callee.hello (groovysh_evaluate:5)
        at Callee$hello.call (Unknown Source)

Note the line “27” doesn’t declare(while the line “3” and line “15” do) the variable “name” so error happens.

Scripts and Classes” has more details.

From my perspective, this is unintuitive and introduces confusion. It also means “script” and “class” in Groovy are executed in different ways under the hood. Most likely it is a trade-off to keep the compatibility with Java.

The method how to add a varible value as the key of a Map entry

This error took me a couple of hours to find the root cause of an error in my code. The trick part is that: when you print the Map in log, you don’t know the type of the entry key, what you see is just the String value… :(

The following answer is from here.

This:

1
map << [it:"value"]

Just uses a key called it. If you wrap it in parentheses:

1
map << [(it):"value"]

It works as you wanted…

If you do:

1
map << ["$it":"value"]

Then, you can see that you have a GStringImpl: as a key rather than a java.lang.String:

1
2
println map.keySet()*.getClass().name
// prints [GStringImpl, GStringImpl, String, GStringImpl ]

(package names omitted for brevity)

Then, you try and look up a GString key with a String, and this fails (see the ‘GStrings aren’t Strings’ section on this page)

This works:

1
map << [(""+it):"value"]

As it just creates a String (by appending it to the empty String)

Anyway…long story short, use [(it):’value’]

Comments