Method created via ExpandoMetaClass is not recognized

View: New views
12 Messages — Rating Filter:   Alert me  

Method created via ExpandoMetaClass is not recognized

by Setya :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

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

Re: Method created via ExpandoMetaClass is not recognized

by Jochen Theodorou :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

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/

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

    http://xircles.codehaus.org/manage_email



Re: Method created via ExpandoMetaClass is not recognized

by Setya :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

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

Re: Method created via ExpandoMetaClass is not recognized

by Roshan Dawrani :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

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

On Fri, Aug 22, 2008 at 9:59 PM, Setya <jsetya@...> wrote:

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.


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

   http://xircles.codehaus.org/manage_email




Re: Method created via ExpandoMetaClass is not recognized

by Setya :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

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

Re: Method created via ExpandoMetaClass is not recognized

by Roshan Dawrani :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

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

On Sat, Aug 23, 2008 at 12:01 AM, Setya <jsetya@...> wrote:

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
Sent from the groovy - user mailing list archive at Nabble.com.


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

   http://xircles.codehaus.org/manage_email







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

    http://xircles.codehaus.org/manage_email

Test.java (1K) Download Attachment
MyJavaInterface.java (94 bytes) Download Attachment
MyGroovyClassImpl.groovy (436 bytes) Download Attachment

Re: Method created via ExpandoMetaClass is not recognized

by Jochen Theodorou :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

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

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

    http://xircles.codehaus.org/manage_email



Re: Method created via ExpandoMetaClass is not recognized

by Jochen Theodorou :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

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

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

    http://xircles.codehaus.org/manage_email



Re: Method created via ExpandoMetaClass is not recognized

by Roshan Dawrani :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

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


On Sat, Aug 23, 2008 at 7:46 PM, Jochen Theodorou <blackdrag@...> wrote:
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

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

  http://xircles.codehaus.org/manage_email




Re: Method created via ExpandoMetaClass is not recognized

by Roshan Dawrani :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

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

On Sat, Aug 23, 2008 at 7:53 PM, Roshan Dawrani <roshandawrani@...> wrote:
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



On Sat, Aug 23, 2008 at 7:46 PM, Jochen Theodorou <blackdrag@...> wrote:
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

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

  http://xircles.codehaus.org/manage_email





Re: Method created via ExpandoMetaClass is not recognized

by Setya :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

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

Re: Method created via ExpandoMetaClass is not recognized

by Jochen Theodorou :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

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/

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

    http://xircles.codehaus.org/manage_email