views:

54

answers:

2

Hi,

I am trying to override the functionality of a method of a java type instance in my Groovy code but I am getting a classcast exception.

I looked at the guide posted here but I can not get it to work.

Since my actual problem is a bit of mess, below is some runnable example code that fails with the same error. In the example I want to override the substring method of an instance of the java.lang.String class. In reality I want to override a method of an instance of a class that does not have a corresponding Groovy implementation, so the answer to my example is not to simply use a Groovy string instance.

class example {
    static void main(args) {
        java.lang.String hey = new java.lang.String("hey")
        ExpandoMetaClass emc = new ExpandoMetaClass( java.lang.String, false )
            emc.substring = {
                       "This is not a very good substring implementation"
                }
            emc.initialize()

        def proxiedHey = new groovy.util.Proxy().wrap(hey)
        proxiedHey.setMetaClass(emc)
        printf proxiedHey.toString()
        printf proxiedHey.substring(1)
    }
}

The above example fails at line 12, i.e printf meh.toString(). The exception thrown is

Caught: java.lang.ClassCastException: groovy.util.Proxy cannot be cast to java.lang.CharSequence at example.main(test.groovy:12)

So, any ideas on what I am doing wrong or if there is another way to solve my problem of adding and/or overriding methods of a java type instance?

I am using Groovy version 1.7.4.

+2  A: 

You are creating an ExpandoMetaClass for java.lang.String, but assigning it to a groovy.util.Proxy. Make a metaClass for groovy.util.Proxy instread, like so:

java.lang.String hey = new java.lang.String("hey")
def proxiedHey = new groovy.util.Proxy().wrap(hey)
ExpandoMetaClass emc = new ExpandoMetaClass( groovy.util.Proxy, false )
emc.substring = {
    "This is not a very good substring implementation"
}
emc.initialize()

proxiedHey.setMetaClass(emc)
printf proxiedHey.toString()
printf proxiedHey.substring(1)
ataylor
A: 

It seems you want to replace the Java method substring(int beginIndex) on the hey String instance only? If so, this is a very simple way to do it:

class example {
    static void main(args) {
        String hey = "hey"

        // override substring on hey only
        hey.metaClass.substring = {int beginIndex ->
           "overriding substring called with arg $beginIndex"
        }

        // Calls the custom implementation of substring
        println hey.substring(2)

        // Calls the JDK implementation of substring        
        println "abcd".substring(2)       
    }
}

I tested this on Groovy version 1.7.2, so it should also work on version 1.7.4

Don
That creates a GString, which is a groovy object. This question is specifically about Java objects that don't have their own metaclass.
ataylor