About Me

My photo
Author of Groovy modules: GBench, GProf, Co-author of a Java book パーフェクトJava, Game Developer at GREE

Tuesday, January 25, 2011

Inside GDK

Groovy has Groovy Development Kit (GDK) that extends Java Development Kit (JDK). Thanks to GDK, We can use many convenient methods with JDK classes. So where are those methods defined? How are those methods added to the JDK classes?


The answer of the first question is "In classes under org.codehaus.groovy.runtime package". I'll introduce some of the classes. 


 - DefaultGroovyMethods: Defines generic methods. But also defines some non-generic methods. In the early version, most of the GDK methods are defined here and Groovy team haven't completely finished moving them yet.
 - DateGroovyMethods: Defines date/time related methods.
 - ProcessGroovyMethods: Defines process-management related methods.
 - SwingGroovyMethods: Defines Swing related methods.


Those methods are all with public static modifier. For example, DefaultGroovyMethods defines dump() method as the following (I introduced dump() method in my previous post, "Generic toString() in Groovy"):
----
public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
    ...
    public static String dump(Object self) {
        ...
    }
    ...
}
----

The answer of the second question is a little complicated. Because to be exact, they aren't added. So how are they called? I'll explain with an example. Let me assume that you call dump() method for an object of java.net.URL class like the following:
----
def url = new URL('http://groovy.codehaus.org/')
url.dump()
----

In this case, Groovy calls dump() method by the following two steps:


1. Generate an object of org.codehaus.groovy.runtime.callsite.MetaMethodSite class that holds the meatadata (groovy.lang.MetaMethod) of DefaultGroovyMethods.dump().
2. Call the MetaMethod object's invoke() method with the URL object argument via the MetaMethodSite object.


So, in a nutshell, this means that Grooovy replaces url.dump() to DefaultGroovyMethods.dump(url) at byte-code generation time. 


You can't use the MetaMethodSite class directly because it's only for Groovy runtime. But don't be disappointed. You can do same thing by using Categories:
----
class MyMethods {
    public static String myDump(Object self) {
        ...
    }
}


use (MyMethods) {
    def url = new URL('http://groovy.codehaus.org/')
    url.myDump()
}
----

   

Tuesday, January 11, 2011

Groovy doesn't have access control, so what do we do?

In Groovy, for now version 1.7, access modifiers don't work. They only play a part in calling our attention, same as comments. See the following example. If access modifiers don't give a false name, accessing to the class members should be restricted.
----
package foo


class Foo {
    protected protectedField
    @PackageScope packagePrivateField
    private privateField


    protected protectedMethod() { }
    private privateMethod() { }
}
----

To ensure that Groovy compiles the Groovy code to Java bytecode as expected, let's disassemble the class file.
----
javap -private Foo
----

The result will be this. No problems. Perfect. It looks as expected.
----
public class Foo extends java.lang.Object implements groovy.lang.GroovyObject{
    protected java.lang.Object protectedField;
    java.lang.Object packageScopeField;
    private java.lang.Object privateField;
    :
    protected java.lang.Object protectedMethod();
    private java.lang.Object privateMethod();
}
----

But accessing them is not restricted. You can access them from anywhere like the following example.
----
package bar


def foo = new Foo()
foo.protectedField
foo.packagePrivateField
foo.privateField
foo.protectedMethod()
foo.privateMethod()
----

According to http://jira.codehaus.org/browse/GROOVY-1875, This bug will be fixed in version 2.0. So what can we do about it now?

What about naming rule? It's probably almost enough to protect from accidents. For example, use underscore prefix like Python or Perl.
----
protected _protectedField
@PackageScope __packageScopeField
private ___privateField


protected _protectedMethod()
private ___privateMethod()
----

It's dirty, complicated. I don't want to use it.

What about closure? If you only need private scope, you can realize it by using closure.
----
package foo


class SecretiveFoo {
  
    SecretiveFoo() {
        def privateField;
        getPrivateField = {
            privateField  
        }
        setPrivateField = { newValue ->
            privateField = newValue
        }
      
        def privateMethod = {
            println 'private method called'
        }
        publicMethod = {
            privateMethod.call()
            // do others
        }
    }
  
    public getPrivateField
    public setPrivateField
    public publicMethod
}
----

----
package bar


def secretiveFoo = new SecretiveFoo()
secretiveFoo.setPrivateField(1)
println secretiveFoo.getPrivateField()
secretiveFoo.publicMethod()
----

The result will be this.
----
1
private method called
----

But this approach costs too much. You can see it by running the following program. Transparent is a normal Groovy class. Secretive is a class that simulates using the approach and generates specified number of closures that accesses a private field. It measures the cost to instantiate them 1000 times.
----
class Secretive {
  
    Secretive(n) {
        def privateField = 0
        actions = []
        (0..n).each {
            actions << { privateField }  
        }
    }
  
    def actions
}


class Transparent {
  
    private privateField = 0
  
}


def maxmem = Runtime.runtime.maxMemory()
def memBefore = maxmem - Runtime.runtime.freeMemory()
def timeBefore = System.nanoTime()
def list = []
(0..<1000).each {
    list << new Secretive(10)
    // list << new Transparent()
}
def timeAfter = System.nanoTime()
def memAfter = maxmem - Runtime.runtime.freeMemory()
def diff = memAfter - memBefore
println "time usage: ${ (timeAfter - timeBefore) * 0.000001 } ms"
println "memory usage: ${ (memAfter - memBefore) * 0.001 } kb"
----

I got the following results. Too heavy. I cannot use it.

TransparentSecretive(10)Serective(20)Serective(30)
Average Time Usage (ms)17.2662.8375.6687.15
Average Memory Usage (kb)1133.672706.193720.965073.95

All we can do is just sit and wait for 2.0 release?

Any idea?

   

Tuesday, January 4, 2011

I wrote a Groovy builder for URLConnection

I wrote a builder for URLConnection, called URLConnectionBuilder. There is already HTTPBuilder for the similar purpose and it works great, but sometimes it's a little exaggerated because it depends on many other third-party modules. Also it has limit that it's only for http URL. URLConnectionBuilder only depends on standard modules and so it's easy to use. And of course you can use it for any URL.


Here is a simple example below:
----
import urlconnbuilder.URLConnectionBuilder;


def connBuilder = new URLConnectionBuilder()
connBuilder.url('http://groovy.codehaus.org/') {
    connect {
        configure (
            requestProperties: [
                'User-Agent': 'Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 5.1',
            ],
            connectTimeout:  1000,
            readTimeout: 1000
        )
        communicate (
            input: { conn, stream ->
                println stream.text
            }
        )
    }
}
----

If you want to try it out, you can download it from here.

   

Saturday, January 1, 2011

Be careful using GString

Groovy has two types for strings, String and GString. Normally, you can use them transparently. See the example below.
----
def s = "1"
println s
println s.class.name
def gs = "${1}"
println gs
println gs.class.name
println s == gs
----

The result will be below.
----
1
java.lang.String
1
org.codehaus.groovy.runtime.GStringImpl
true
----

But there are exceptions. In the next example, I try to shuffle the officer agent pairs (They are the characters from the One Piece manga).
----
def pairOfficerAgents(List femaleAgents) {
    def pairs = [:]
    (0..5).each{ no ->
        pairs.put("Mr. $no", femaleAgents[no]) 
    }
    pairs
}

def femaleAgents = ["Ms. All Sunday", "Ms. Doublefinger", "None", "Ms. Golden Week", "Ms. Merry Christmas", "Ms. Valentine"]
def officerAgentPairs = pairOfficerAgents(femaleAgents)
println(officerAgentPairs)
println("Shuffle!")
Collections.shuffle(femaleAgents)
officerAgentPairs = pairOfficerAgents(femaleAgents)
println(officerAgentPairs
----

The result will be like this.
----
[Mr. 0:Ms. All Sunday, Mr. 1:Ms. Doublefinger, Mr. 2:None, Mr. 3:Ms. Golden Week, Mr. 4:Ms. Merry Christmas, Mr. 5:Ms. Valentine]
Shuffle!
[Mr. 0:Ms. Merry Christmas, Mr. 1:Ms. Doublefinger, Mr. 2:None, Mr. 3:Ms. All Sunday, Mr. 4:Ms. Golden Week, Mr. 5:Ms. Valentine]
----

OK, they are successfully shuffled. Then I will try to print out the partner of the Mr. 0.
----
println officerAgentPairs.get("Mr. 0")
----

Contrary to your expectations, the result will be this.
----
null
----

Why? First, String and GString do not have the same hash code even if they express the same string because GString is mutable. Second, Groovy doesn't extend HashMap's put() method to be able to use GString as key (This is the known issue that the Groovy team says "won't fix"). So you need to make GString into String by yourself.  

There are some ways to make GString into String in the example above.

Use subscript operator or putAt() method instead of put() method:
----
pairs["Mr. $no"] = femaleAgents[no]
----
----
pairs.putAt("Mr. $no", femaleAgents[no]) 
----

Use toString() method:
----
pairs.put("Mr. $no".toString(), femaleAgents[no])
----

Use the as keyword:
----
pairs.put("Mr. $no" as String, femaleAgents[no])
----

Assign to a variable that is statically typed as String:
----
String maleAgent = "Mr. $no"
pairs.put(maleAgent , femaleAgents[no])
----

I personally recommend the first way, using subscript operator. Because it's more Groovy style, and it's the shortest among the ways above.