groovy-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Basurita <>
Subject adding metamethods to pojos from java
Date Fri, 20 Oct 2017 23:58:01 GMT
Hi, it's stubborn me again :-)

I have a POJO (let's call it `Context`) from a big Java library.
This library has been historically used only from Java, but I've been wanting to add Groovy
scripting to it.

The Context class works similarly to a Map: it has a few `get(Object key)` and `set(Object
key, Object value)` methods.
I've spent many days trying to provide a Groovy syntax, so that users of the class can say
`ctx.prop= val` instead of calling `ctx.put("foo", val)`

Context it's not a Map, it *will not* be a Map, it *will not* be a GroovyObject, etc.
(I don't want to add any Groovy dependency to the project, only to the add-on module that
I'm writing)

I know perfectly well how to do it *from Groovy code*, something like:
(1)   Context.metaClass.getProperty = { String k -> return delegate.get(k) }

Yes, adding the above in a Groovy script works for POJOs (despite some doubts by Jochen a
few days ago :-) )

But for some reason (call my stubborn all you want), I want to do it *from Java*, in the code
that sets up the *optional* Groovy module for this library.
I've tried dozens of combinations using tricks such as creating an ExpandoMetaClass and calling
`registerInstanceMethod` with a Closure, or with a
MetaMethod, and setting the MetaClass in the registry.
Or using `InvokeHelper.setProperty` in its different forms.
I've done all kinds of initializingRegisteringGettingSettingMetaDoingCalling... nothing works.

To be fair, I can add new methods with the equivalent of `expandoMCforContext.registerInstanceMethod("someMethod",
and then doing  `ctx.someMethod()` from Groovy will work!

But it won't work for `get/setProperty`.

I've also tried an extension module, which works nicely for `someStupidMethod()`, but not
for `get/setProperty`
Let's be clear: if I add for example `getProperty(String)`, I can call it as long as I do
`ctx.getProperty("foo")` but that's not the idea! I want to
say ``

I've gone the length of step-debugging the code to see what happens with the groovy way of
doing things, as given in (1), but I haven't been able to
reproduce it from Java.

1) I would like to know if there's SOME WAY to do it from Java which is not overly complicated
(I've googled and googled and found zero examples).

2) For the time being, I've humiliated myself and done the following, and I'd also like to
know if it's a "proper" way:
I created a short groovy script `ContextMagic.groovy` which I put under the jar resources,
similar to
    def mc= Context.metaClass
    mc.getProperty= { String name -> return delegate.get(name) }
    mc.setProperty= { String name, Object val ->  delegate.put(name, val) }

And then, from the initializing Java code I do
    ClassLoader thisCL= this.getClass().getClassLoader();
    URL scriptURL= thisCL.getResource("path/to/ContextMagic.groovy");
    GroovyShell sh= new GroovyShell();
    sh.evaluate(new GroovyCodeSource(scriptURL));

Is the above correct? It works, but is this a proper way to do it?
Could the meta methods be "forgotten" after a while if classes/classloaders/whatever gets
unloaded by garbage collecting? (how can I prevent that?)

sorry for the long and frustation-filled mail :-)


View raw message