tags:

views:

83

answers:

3

I'd like to re-implement a method of a Java class. For example, for "hi".length() to return 4. (How) Can I do that?

I know using SomeClass.metaClass I can get a reference to an existing method and define new (or overriding) method, but I can't seem to be able to do that for existing Java methods.

+1  A: 

Seems like it could be possible by abusing String metaClass. But the attempt I've done so far in groovy console didn't led to the expected result :

def oldLength = String.metaClass.length
String.metaClass.length = { ->
    return oldLength+10;
}

println "hi".length()

outputs the sad 2

I think you could take a look at Proxy MetaClass or Delegating metaClass.

Riduidel
I think the problem is related to this issue: http://jira.codehaus.org/browse/GROOVY-3493
tim_yates
Seems so, this works: String.metaClass.invokeMethod = { String methodName, args -> println("hi")}"hi".length() // prints "hi"
IttayD
Why has this answer been accepted when by the author's own admission it doesn't actually work?
Don
Mayube did I provide enough information to let it conclude by himself. But, as you state, I don't give the full answer here (however his comment seems to indicate he find the answer).
Riduidel
i accepted because it was the closest to an answer at the time (i did know about this approach)
IttayD
+1  A: 

If you did redefine it, it would only work in Groovy code. Groovy can't change the way Java code executes.

In Groovy, "hi".length() is roughly equivalent to this Java:

stringMetaClass.invokeMethod("hi","length");

Because Groovy doesn't actually call length directly, metaClass tricks work in Groovy code. But Java doesn't know about MetaClasses, so there is no way to make this work.

noah
yes, please, show me how to do it for groovy only
IttayD
+1  A: 

Using Groovy, you can replace any method (even those of final classes) with your own implementation. Method replacement in Groovy uses the meta-object protocol, not inheritance.

Here's the example you requested, i.e. how to make String.length() always return 4

// Redefine the method
String.metaClass.invokeMethod = { name, args ->

    def metaMethod = delegate.metaClass.getMetaMethod(name, args)
    def result = metaMethod.invoke(delegate, args)

    name == 'length' ? 4 : result
}

// Test it
assert "i_do_not_have_4_chars".length() == 4
Don
note to others that may wonder why this wasn't accepted as an answer: it was submitted after i commented that this is the solution in the answer above
IttayD
You can unaccept the other answer and accept this one if you feel it's better. Just click the green check mark to unaccept it.
Don