[groovy-user] Method created via ExpandoMetaClass is not recognized

16 views
Skip to first unread message

Setya

unread,
Aug 22, 2008, 10:45:52 AM8/22/08
to us...@groovy.codehaus.org

Hi all,

I'm trying to implement Java interface with Groovy as follows:

//MyGroovyClassImpl.groovy
class MyGroovyClassImpl implements MyJavaInterface
{
MyGroovyClassImpl()
{
MyGroovyClassImpl.metaClass.getNext = {-> println 'This is next
command.';}
}
}

Then I call above class from Java as follows:

//Java code to access MyGroovyClassImpl.groovy
GroovyClassLoader gcl = new GroovyClassLoader();
Class cls = gcl.parseClass(new File(<path to MyGroovyClassImpl.groovy>));
Object obj = cls.newInstance();
MyJavaInterface myInterface = MyJavaInterface.class.cast(obj);

Binding binding = new Binding();
binding.setVariable("myInterface",myInterface);

GroovyShell gs = new GroovyShell(binding);
gs.evaluate("myInterface.next");


The last line produces the following exception:
groovy.lang.MissingPropertyException: No such property: next for class:
ScriptExecutionContext
at
org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:50)
at
org.codehaus.groovy.runtime.ScriptBytecodeAdapter.getProperty(ScriptBytecodeAdapter.java:479)
at Script1.run(Script1.groovy)
at groovy.lang.GroovyShell.evaluate(GroovyShell.java:543)
at groovy.lang.GroovyShell.evaluate(GroovyShell.java:518)
...

I've added ExpandoMetaClass.enableGlobally(), but the problem persists.

Any help would be greatly appreciated.

Regards,

Setya
--
View this message in context: http://www.nabble.com/Method-created-via-ExpandoMetaClass-is-not-recognized-tp19108704p19108704.html
Sent from the groovy - user mailing list archive at Nabble.com.


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email


Jochen Theodorou

unread,
Aug 22, 2008, 11:16:44 AM8/22/08
to us...@groovy.codehaus.org
Setya schrieb:

> Hi all,
>
> I'm trying to implement Java interface with Groovy as follows:
>
> //MyGroovyClassImpl.groovy
> class MyGroovyClassImpl implements MyJavaInterface
> {
> MyGroovyClassImpl()
> {
> MyGroovyClassImpl.metaClass.getNext = {-> println 'This is next
> command.';}
> }
> }
[...]

please try:

> //MyGroovyClassImpl.groovy
> class MyGroovyClassImpl implements MyJavaInterface
> {
> MyGroovyClassImpl()
> {
> MyGroovyClassImpl.metaClass.getNext = {-> println 'This is next command.';}

> this.metaClass = null
> }
> }

because at the point you add the method the class has already a per
instance meta class, but you call will only affect global meta
classes... also... do you really want to do that each time? how about

> //MyGroovyClassImpl.groovy
> class MyGroovyClassImpl implements MyJavaInterface {

> static {
> this.metaClass.getNext = {-> println 'This is next command.';}{
> }
> }

then it will be executed only once and I think the hack with
this.metaClass = null is also not needed any more.

> The last line produces the following exception:
> groovy.lang.MissingPropertyException: No such property: next for class:
> ScriptExecutionContext
> at
> org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:50)
> at
> org.codehaus.groovy.runtime.ScriptBytecodeAdapter.getProperty(ScriptBytecodeAdapter.java:479)
> at Script1.run(Script1.groovy)
> at groovy.lang.GroovyShell.evaluate(GroovyShell.java:543)
> at groovy.lang.GroovyShell.evaluate(GroovyShell.java:518)
> ...
>
> I've added ExpandoMetaClass.enableGlobally(), but the problem persists.

you did, hmm.. so maybe I am wrong then... unless... is it the first
thing you do?

bye blackdrag

--
Jochen "blackdrag" Theodorou
The Groovy Project Tech Lead (http://groovy.codehaus.org)
http://blackdragsview.blogspot.com/
http://www.g2one.com/

Setya

unread,
Aug 22, 2008, 12:29:14 PM8/22/08
to us...@groovy.codehaus.org

Hi blackdrag,

Thanks for quick response.

I've tried your suggestions, but none of them works.

Regarding ExpandoMetaClass.enableGlobally(), If I put it in
MyGroovyClassImpl.groovy than the GroovyClassLoader won't parse the file as
instance of MyJavaInterface. If I add it when evaluating the script, it
doesn't take effect.

But If I put those scripts in 1 file it works as expected as follows:

class MyGroovyClassImpl


{
MyGroovyClassImpl()
{
MyGroovyClassImpl.metaClass.getNext = {->println 'This is next

command.';};
}
}
ExpandoMetaClass.enableGlobally();
def context = new MyGroovyClassImpl();
context.next;

Regards,

Setya
--
View this message in context: http://www.nabble.com/Method-created-via-ExpandoMetaClass-is-not-recognized-tp19108704p19110800.html


Sent from the groovy - user mailing list archive at Nabble.com.

Roshan Dawrani

unread,
Aug 22, 2008, 2:10:55 PM8/22/08
to us...@groovy.codehaus.org
I am also trying to learn Groovy and I tried this thing and for me both the things worked -

1) setting this.metaClass = null in the MyGroovyClassImpl constructor in MyGroovyClassImpl.groovy

2) setting MyGroovyClassImpl.metaClass.getNext in a static block so that it happens only once.

Can you please take out a few moments and explain the effect "this.metaClass = null" internally has? Does setting it null make the instance use the global metaclass that has been affected by setting "MyGroovyClassImpl.metaClass.getNext"?

Regards,
Roshan

Setya

unread,
Aug 22, 2008, 2:31:19 PM8/22/08
to us...@groovy.codehaus.org

Hi,

>
> I am also trying to learn Groovy and I tried this thing and for me both
> the
> things worked -
>
> 1) setting this.metaClass = null in the MyGroovyClassImpl constructor in
> MyGroovyClassImpl.groovy
>
> 2) setting MyGroovyClassImpl.metaClass.getNext in a static block so that
> it
> happens only once.
>
> Can you please take out a few moments and explain the effect
> "this.metaClass
> = null" internally has? Does setting it null make the instance use the
> global metaclass that has been affected by setting
> "MyGroovyClassImpl.metaClass.getNext"?

Does your class implement a Java (not Groovy) interface ? and you invoke the
script exactly the way I did it from Java (not Groovy) ?

Regards,

Setya

--
View this message in context: http://www.nabble.com/Method-created-via-ExpandoMetaClass-is-not-recognized-tp19108704p19113164.html

Roshan Dawrani

unread,
Aug 22, 2008, 2:47:20 PM8/22/08
to us...@groovy.codehaus.org
Yes. I have defined a Java interface whose implementation is a Groovy class and then I am invoking this impl groovy class again from a Java class using GroovyShell/GroovyClassLoader - I set it up exactly as you mentioned in your first mail. I am attaching the code files that worked for me.

It is just that even after seeing it work, I did not understand the meaning of "this.metaClass = null". Does setting it to null make it re-assign its own per instance metaClass using the newly modified global EMC?

rgds,
Roshan
Test.java
MyJavaInterface.java
MyGroovyClassImpl.groovy

Jochen Theodorou

unread,
Aug 23, 2008, 10:16:02 AM8/23/08
to us...@groovy.codehaus.org
Setya schrieb:

> Hi blackdrag,
>
> Thanks for quick response.
>
> I've tried your suggestions, but none of them works.

does not? hmm... should have.. do you use 1.5.6?

> Regarding ExpandoMetaClass.enableGlobally(), If I put it in
> MyGroovyClassImpl.groovy than the GroovyClassLoader won't parse the file as
> instance of MyJavaInterface. If I add it when evaluating the script, it
> doesn't take effect.
>
> But If I put those scripts in 1 file it works as expected as follows:
>
> class MyGroovyClassImpl
> {
> MyGroovyClassImpl()
> {
> MyGroovyClassImpl.metaClass.getNext = {->println 'This is next
> command.';};
> }
> }
> ExpandoMetaClass.enableGlobally();
> def context = new MyGroovyClassImpl();
> context.next;

ok, imagine you need to call a method or set a field/property on a class
in Groovy. To accomplish this, Groovy needs a MetaClass. Now, this
happens not only for code you see, but also for code you do not see...
for example to set fields in the constructor

This means when the first line of your code is executed in the
constructor you already need a MetaClass. Therefor you can not affect
the current meta class with ExpandoMetaClass.enableGlobally(); in the
constrcutor, beause the point where this would affect the meta class is
already passed.

bye blackdrag

Jochen Theodorou

unread,
Aug 23, 2008, 10:20:36 AM8/23/08
to us...@groovy.codehaus.org
Roshan Dawrani schrieb:

> I am also trying to learn Groovy and I tried this thing and for me both
> the things worked -

so they do work... strange

> 1) setting this.metaClass = null in the MyGroovyClassImpl constructor in
> MyGroovyClassImpl.groovy

well... null is an invalid meta class. But we ned one and the global
meta class is used to set the per instance meta class. That means if the
global meta class is changed and the current meta class of the object is
"delegted", then the global meta class becomes the new current meta class.

> 2) setting MyGroovyClassImpl.metaClass.getNext in a static block so that
> it happens only once.

this works, because at this point the meta class for the class is not
yet set.. since there is no instance yet. So if you change the global
meta class and then make an instance, then you get the global metaclass
as current meta class for the current instance.

so it is two different effects


bye blackdrag

Roshan Dawrani

unread,
Aug 23, 2008, 10:23:36 AM8/23/08
to us...@groovy.codehaus.org
The bit that - the per-instance meta class is already set by the time we are in the constructor - was a little clear. I was not sure what effect was setting it to null having after modifying the metaclass (adding getNextI() to it). Does making it null make groovy set it again and this time using the just-modified meta-class?

rgds,
Roshan

Roshan Dawrani

unread,
Aug 23, 2008, 10:25:27 AM8/23/08
to us...@groovy.codehaus.org
Ok, I understand it better now. Thanks for explaining. Please ignore my last mail. I think our last mails cross each other on the way.

rgds,
Roshan

Setya

unread,
Aug 23, 2008, 2:48:00 PM8/23/08
to us...@groovy.codehaus.org

Hi,

One thing that I forgot to mention is that if I tried your suggestions in
Eclipse using plain JUnit Test, it worked as expected, but when I run it on
JUnit Plug-in Test it didn't. Is this a known issue when adding
method/property via ExpandoMetaClass in Eclipse Equinox envronment ?

Regards,

Setya
--
View this message in context: http://www.nabble.com/Method-created-via-ExpandoMetaClass-is-not-recognized-tp19108704p19124043.html


Sent from the groovy - user mailing list archive at Nabble.com.

Jochen Theodorou

unread,
Aug 23, 2008, 6:13:53 PM8/23/08
to us...@groovy.codehaus.org
Roshan Dawrani schrieb:

> The bit that - the per-instance meta class is already set by the time we
> are in the constructor - was a little clear. I was not sure what effect
> was setting it to null having after modifying the metaclass (adding
> getNextI() to it). Does making it null make groovy set it again and this
> time using the just-modified meta-class?

yes

byeblackdrag

--
Jochen "blackdrag" Theodorou
The Groovy Project Tech Lead (http://groovy.codehaus.org)
http://blackdragsview.blogspot.com/
http://www.g2one.com/

---------------------------------------------------------------------

Reply all
Reply to author
Forward
0 new messages