a standard way to enhance the GDK using Java code using META-INF/services/groovy/groovyMethods files...

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

a standard way to enhance the GDK using Java code using META-INF/services/groovy/groovyMethods files...

by James.Strachan :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I've just got an excuse to play with Groovy again after a rather long
quiet time; I'm busy hacking a little Groovy DSL for Apache Camel...
http://activemq.apache.org/camel/
(I can imagine the logo already BTW; a camel with shades and flared
disco trousers... ;-)

Firstly - great work everyone! Groovy's really come on in leaps and
bounds since I last used it. Also the IDEA plugin is amazing! (I found
I had to use the latest EAP; I struggled with 7.0 M2 to no avail).

So I found the easiest way to implement my little DSL was to add some
extra groovy methods to various types. (These methods needed to be
added to some base classes too, so the GDK type additions being a
really nice way to solve this issue).

I know I can do this with categories; but I really wanted to hard-bake
in these extra methods with the actual library so its not really
possible to not have these methods around. i.e. I'd like
camel-groovy.jar being on the classpath to auto-register some groovy
methods for working with Camel in a groovy way.

I took a quick peek at the grails stuff for adding extensions and
didn't quite grok it but it looked like it was doing clever stuff
doing pattern matching and whatnot - I guess for the find by methods
for ORM etc. The methods I need to add are pretty simple and need to
be typed (need multiple methods with same name but different
parameters). I wondered what the current approach was in Groovy?

I kinda liked the idea of a way to expose new groovy methods in other
libraries that just kinda gets wired up by default if the library is
on the classpath; particular for library developers to be able to ship
a separate groovy jar with their library for folks wishing to work
with groovy and their library.

I couldn't see any other option (forgive me if I missed something) so
took a little stab at a simple implementation. Namely, if a file
called

  META-INF/services/groovy/groovyMethods

is found on the classpath then its parsed (lines starting with #
ignored) then any non-whitespace lines are tokenized on ",", removing
all whitespace and then assumed to be a Class which defines instance
groovy methods. Then for static methods we look for...

  META-INF/services/groovy/groovyStaticMethods

So in Camel's case, we write a file called
META-INF/services/groovy/groovyMethods that contains
"org.apache.camel.groovy.CamelGroovyMethods" and then hey presto;
anyone with the camel-groovy jar on their classpath gets nice DSL
magic.


Its a pretty trivial patch - and is really easy to back-out if there's
a better way of doing this. I don't seem to have commit karma any
more, so I've raised a JIRA and attached the patch for review...
http://jira.codehaus.org/browse/GROOVY-2116

I'm sure there's another way tinkering with the
MetaClassRegister/MetaClass stuff; I just liked this simple approach
as its nice and simple & hard to break & is barely any code etc.

Thoughts?
--
James
-------
http://macstrac.blogspot.com/

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

    http://xircles.codehaus.org/manage_email


Re: a standard way to enhance the GDK using Java code using META-INF/services/groovy/groovyMethods files...

by Joachim Baumann :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi James,

first of all, never having met you, let me say: A big thanks for
inventing Groovy, even if you went on to greener (or at least other)
pastures. :-)

You can add your own metaclasses by simply placing them in the right
spot. Here is an example:

---------------------------------------------------------------------
package groovy.runtime.metaclass.de.groovybuch.kap7

import java.lang.reflect.Modifier

class ExtendMeMetaClass extends MetaClassImpl {
    ExtendMeMetaClass(MetaClassRegistry registry,
                      Class objClass) {
        super(registry, objClass)
        getClass().declaredMethods.each { method ->
            if(Modifier.isStatic(method.modifiers)
                    && !method.name.contains('$')) {
                addNewInstanceMethod(method)
            }
        }
        super.initialize()
    }
    static addedMethod(obj, name){
        return "Hallo, $name"
    }
}
---------------------------------------------------------------------
This metaclass is used for the class de.groovybuch.kap7.ExtendMe. The
metaclass is named after the class for which it is used
(<classname>MetaClass) and placed in the package
groovy.runtime.metclass.<package of class>.

Now this metaclass simply adds all static methods it contains to the
methods of the class. In the simple case above this is only the method
addedMethod, that when called like this

extendMe.addedMethod("James)

returns "Hallo, James".

Since this class is packed into your jar, it can never be lost.

This an existing mechanism you could use. The one remaining problem: You
have to create a metaclass like the above one for every class you
modify. But in my opinion this is not really a disadvantage, because the
association is quite clear.

Cheers, Joachim

James Strachan schrieb:

> I've just got an excuse to play with Groovy again after a rather long
> quiet time; I'm busy hacking a little Groovy DSL for Apache Camel...
> http://activemq.apache.org/camel/
> (I can imagine the logo already BTW; a camel with shades and flared
> disco trousers... ;-)
>
> Firstly - great work everyone! Groovy's really come on in leaps and
> bounds since I last used it. Also the IDEA plugin is amazing! (I found
> I had to use the latest EAP; I struggled with 7.0 M2 to no avail).
>
> So I found the easiest way to implement my little DSL was to add some
> extra groovy methods to various types. (These methods needed to be
> added to some base classes too, so the GDK type additions being a
> really nice way to solve this issue).
>
> I know I can do this with categories; but I really wanted to hard-bake
> in these extra methods with the actual library so its not really
> possible to not have these methods around. i.e. I'd like
> camel-groovy.jar being on the classpath to auto-register some groovy
> methods for working with Camel in a groovy way.
>
> I took a quick peek at the grails stuff for adding extensions and
> didn't quite grok it but it looked like it was doing clever stuff
> doing pattern matching and whatnot - I guess for the find by methods
> for ORM etc. The methods I need to add are pretty simple and need to
> be typed (need multiple methods with same name but different
> parameters). I wondered what the current approach was in Groovy?
>
> I kinda liked the idea of a way to expose new groovy methods in other
> libraries that just kinda gets wired up by default if the library is
> on the classpath; particular for library developers to be able to ship
> a separate groovy jar with their library for folks wishing to work
> with groovy and their library.
>
> I couldn't see any other option (forgive me if I missed something) so
> took a little stab at a simple implementation. Namely, if a file
> called
>
>   META-INF/services/groovy/groovyMethods
>
> is found on the classpath then its parsed (lines starting with #
> ignored) then any non-whitespace lines are tokenized on ",", removing
> all whitespace and then assumed to be a Class which defines instance
> groovy methods. Then for static methods we look for...
>
>   META-INF/services/groovy/groovyStaticMethods
>
> So in Camel's case, we write a file called
> META-INF/services/groovy/groovyMethods that contains
> "org.apache.camel.groovy.CamelGroovyMethods" and then hey presto;
> anyone with the camel-groovy jar on their classpath gets nice DSL
> magic.
>
>
> Its a pretty trivial patch - and is really easy to back-out if there's
> a better way of doing this. I don't seem to have commit karma any
> more, so I've raised a JIRA and attached the patch for review...
> http://jira.codehaus.org/browse/GROOVY-2116
>
> I'm sure there's another way tinkering with the
> MetaClassRegister/MetaClass stuff; I just liked this simple approach
> as its nice and simple & hard to break & is barely any code etc.
>
> Thoughts?
>  

--
Xinaris GmbH
Flüsselweg 10, 76646 Bruchsal
Tel.: +(49)7251/39264-21    | Sitz der Gesellschaft: Bruchsal
Fax:  +(49)7251/39264-29    | Registergericht: AG Mannheim HRB 232791
WWW:  http://www.xinaris.de | Geschäftsführer: Dr. Joachim Baumann
Mail: info@...       | USt-ID DE 242 975 278


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

    http://xircles.codehaus.org/manage_email


Re: a standard way to enhance the GDK using Java code using META-INF/services/groovy/groovyMethods files...

by Jochen Theodorou :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi James,

long time no see ;)

James Strachan schrieb:
[...]
> I know I can do this with categories; but I really wanted to hard-bake
> in these extra methods with the actual library so its not really
> possible to not have these methods around. i.e. I'd like
> camel-groovy.jar being on the classpath to auto-register some groovy
> methods for working with Camel in a groovy way.

The problem we haven't solved with this yet, is the scope of this
ability. If you use multiple DSL extensions then it might happen, that
you get them mixed up. Even with categories you get this problem, just
it is limited to one thread.

What I would like to have is to have an extension just in the scope of
the class, and I have plans for that in the next generation of
MetaClasses.. but that way would lack the automatic approach you would
like to have.

I would like to have at last a collision detection or error handling of
some kind.

> I took a quick peek at the grails stuff for adding extensions and
> didn't quite grok it but it looked like it was doing clever stuff
> doing pattern matching and whatnot - I guess for the find by methods
> for ORM etc. The methods I need to add are pretty simple and need to
> be typed (need multiple methods with same name but different
> parameters). I wondered what the current approach was in Groovy?

the same as when you left ;) Well.. unless you want to use
ExpandoMetaclass for this. Or MetaclassCreationHandle

bye blackdrag


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

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

    http://xircles.codehaus.org/manage_email


Re: a standard way to enhance the GDK using Java code using META-INF/services/groovy/groovyMethods files...

by James.Strachan :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

BTW here's the camel-groovy module which uses this extension...
http://svn.apache.org/repos/asf/activemq/camel/trunk/components/camel-groovy/

e.g. here's the META-INF/services file..
http://svn.apache.org/repos/asf/activemq/camel/trunk/components/camel-groovy/src/main/resources/META-INF/services/groovy/groovyMethods

which maps to these new methods...
http://svn.apache.org/repos/asf/activemq/camel/trunk/components/camel-groovy/src/main/java/org/apache/camel/groovy/CamelGroovyMethods.java

and here's an example of the DSL. (Yes I know, its not that DSL-ish yet! :)
http://svn.apache.org/repos/asf/activemq/camel/trunk/components/camel-groovy/src/test/resources/org/apache/camel/groovy/example/GroovyRoutes.groovy


On 9/12/07, James Strachan <james.strachan@...> wrote:

> I've just got an excuse to play with Groovy again after a rather long
> quiet time; I'm busy hacking a little Groovy DSL for Apache Camel...
> http://activemq.apache.org/camel/
> (I can imagine the logo already BTW; a camel with shades and flared
> disco trousers... ;-)
>
> Firstly - great work everyone! Groovy's really come on in leaps and
> bounds since I last used it. Also the IDEA plugin is amazing! (I found
> I had to use the latest EAP; I struggled with 7.0 M2 to no avail).
>
> So I found the easiest way to implement my little DSL was to add some
> extra groovy methods to various types. (These methods needed to be
> added to some base classes too, so the GDK type additions being a
> really nice way to solve this issue).
>
> I know I can do this with categories; but I really wanted to hard-bake
> in these extra methods with the actual library so its not really
> possible to not have these methods around. i.e. I'd like
> camel-groovy.jar being on the classpath to auto-register some groovy
> methods for working with Camel in a groovy way.
>
> I took a quick peek at the grails stuff for adding extensions and
> didn't quite grok it but it looked like it was doing clever stuff
> doing pattern matching and whatnot - I guess for the find by methods
> for ORM etc. The methods I need to add are pretty simple and need to
> be typed (need multiple methods with same name but different
> parameters). I wondered what the current approach was in Groovy?
>
> I kinda liked the idea of a way to expose new groovy methods in other
> libraries that just kinda gets wired up by default if the library is
> on the classpath; particular for library developers to be able to ship
> a separate groovy jar with their library for folks wishing to work
> with groovy and their library.
>
> I couldn't see any other option (forgive me if I missed something) so
> took a little stab at a simple implementation. Namely, if a file
> called
>
>   META-INF/services/groovy/groovyMethods
>
> is found on the classpath then its parsed (lines starting with #
> ignored) then any non-whitespace lines are tokenized on ",", removing
> all whitespace and then assumed to be a Class which defines instance
> groovy methods. Then for static methods we look for...
>
>   META-INF/services/groovy/groovyStaticMethods
>
> So in Camel's case, we write a file called
> META-INF/services/groovy/groovyMethods that contains
> "org.apache.camel.groovy.CamelGroovyMethods" and then hey presto;
> anyone with the camel-groovy jar on their classpath gets nice DSL
> magic.
>
>
> Its a pretty trivial patch - and is really easy to back-out if there's
> a better way of doing this. I don't seem to have commit karma any
> more, so I've raised a JIRA and attached the patch for review...
> http://jira.codehaus.org/browse/GROOVY-2116
>
> I'm sure there's another way tinkering with the
> MetaClassRegister/MetaClass stuff; I just liked this simple approach
> as its nice and simple & hard to break & is barely any code etc.
>
> Thoughts?
> --
> James
> -------
> http://macstrac.blogspot.com/
>


--
James
-------
http://macstrac.blogspot.com/

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

    http://xircles.codehaus.org/manage_email


Re: a standard way to enhance the GDK using Java code using META-INF/services/groovy/groovyMethods files...

by James.Strachan :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On 9/12/07, Joachim Baumann <joachim.baumann@...> wrote:
> Hi James,
>
> first of all, never having met you, let me say: A big thanks for
> inventing Groovy, even if you went on to greener (or at least other)
> pastures. :-)

Thanks! just different pastures...


> You can add your own metaclasses by simply placing them in the right
> spot. Here is an example:

Aha! I knew there must have been a nice way to do this! Many thanks!

FWIW I still prefer my option as an extra way of doing it; its
particularly useful for writing a whole bunch of new methods on
multiple types in a single simple class; but see the attraction of the
other method too.

I did try using your approach but it only seems to work for the end
class, not any base classes. I basically wanted to add methods to base
classes (e.g. think of adding methods to java.lang.Object). So I still
think there's merit in my approach as well.

--
James
-------
http://macstrac.blogspot.com/

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

    http://xircles.codehaus.org/manage_email


Re: a standard way to enhance the GDK using Java code using META-INF/services/groovy/groovyMethods files...

by James.Strachan :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On 9/12/07, Jochen Theodorou <blackdrag@...> wrote:
> Hi James,
>
> long time no see ;)

Yeah! :)

> James Strachan schrieb:
> [...]
> > I know I can do this with categories; but I really wanted to hard-bake
> > in these extra methods with the actual library so its not really
> > possible to not have these methods around. i.e. I'd like
> > camel-groovy.jar being on the classpath to auto-register some groovy
> > methods for working with Camel in a groovy way.
>
> The problem we haven't solved with this yet, is the scope of this
> ability. If you use multiple DSL extensions then it might happen, that
> you get them mixed up. Even with categories you get this problem, just
> it is limited to one thread.

Someone inside a category could always remove methods I guess. I'm
more bothered about folks being able to add nice extra groovy features
into their libraries; I think we need an easy, default way to do that.


> What I would like to have is to have an extension just in the scope of
> the class, and I have plans for that in the next generation of
> MetaClasses.. but that way would lack the automatic approach you would
> like to have.
>
> I would like to have at last a collision detection or error handling of
> some kind.

Sounds fine with me. So long as there's an easy way to add extension
methods either from Java or Groovy code thats auto-discovered, I'm
happy.


> > I took a quick peek at the grails stuff for adding extensions and
> > didn't quite grok it but it looked like it was doing clever stuff
> > doing pattern matching and whatnot - I guess for the find by methods
> > for ORM etc. The methods I need to add are pretty simple and need to
> > be typed (need multiple methods with same name but different
> > parameters). I wondered what the current approach was in Groovy?
>
> the same as when you left ;) Well.. unless you want to use
> ExpandoMetaclass for this. Or MetaclassCreationHandle

So anyone fancy applying my patch as a first stab at an easy way to
extend the GDK?

--
James
-------
http://macstrac.blogspot.com/

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

    http://xircles.codehaus.org/manage_email


Re: a standard way to enhance the GDK using Java code using META-INF/services/groovy/groovyMethods files...

by Tom Nichols :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Actually I like this idea.  How about...

Look at _everything_ under that folder on the classpath, and parse all
of them for extensions.  That way, library x can contain extension
methods for classes A and B, and library y can contain extensions for
C.  Since they are all parsed at once, it would be a "fail fast" if a
second library contained conflicting extension methods.  Or you could
just say classpath order determines preference.

I found a way to hard-bake categories into the metaclass:

class XPathCategory {
  static getNode( node, expression ) {
    ...
  }
  //other methods

  static apply() {
    addMethod( XPathCategory.&getNode )
    //add other methods...
  }
       
  private static addMethod( newMethod ) {
    Node.metaClass."$newMethod.method" << { exp -> newMethod( delegate, exp ) }
    NodeList.metaClass."$newMethod.method" << { exp -> newMethod(
delegate, exp ) }
  }
}

Attached is the full example for XPath methods on an org.w3c.dom.Node
and NodeList.  (Don't concentrate too much on the usefulness of this
specific application.)  If that XPathCategory class was put into a
certain classpath location and automatically parsed at startup and
apply() called, that would be super-awesome :-)

-Tom


On 9/12/07, James Strachan <james.strachan@...> wrote:

> I've just got an excuse to play with Groovy again after a rather long
> quiet time; I'm busy hacking a little Groovy DSL for Apache Camel...
> http://activemq.apache.org/camel/
> (I can imagine the logo already BTW; a camel with shades and flared
> disco trousers... ;-)
>
> Firstly - great work everyone! Groovy's really come on in leaps and
> bounds since I last used it. Also the IDEA plugin is amazing! (I found
> I had to use the latest EAP; I struggled with 7.0 M2 to no avail).
>
> So I found the easiest way to implement my little DSL was to add some
> extra groovy methods to various types. (These methods needed to be
> added to some base classes too, so the GDK type additions being a
> really nice way to solve this issue).
>
> I know I can do this with categories; but I really wanted to hard-bake
> in these extra methods with the actual library so its not really
> possible to not have these methods around. i.e. I'd like
> camel-groovy.jar being on the classpath to auto-register some groovy
> methods for working with Camel in a groovy way.
>
> I took a quick peek at the grails stuff for adding extensions and
> didn't quite grok it but it looked like it was doing clever stuff
> doing pattern matching and whatnot - I guess for the find by methods
> for ORM etc. The methods I need to add are pretty simple and need to
> be typed (need multiple methods with same name but different
> parameters). I wondered what the current approach was in Groovy?
>
> I kinda liked the idea of a way to expose new groovy methods in other
> libraries that just kinda gets wired up by default if the library is
> on the classpath; particular for library developers to be able to ship
> a separate groovy jar with their library for folks wishing to work
> with groovy and their library.
>
> I couldn't see any other option (forgive me if I missed something) so
> took a little stab at a simple implementation. Namely, if a file
> called
>
>   META-INF/services/groovy/groovyMethods
>
> is found on the classpath then its parsed (lines starting with #
> ignored) then any non-whitespace lines are tokenized on ",", removing
> all whitespace and then assumed to be a Class which defines instance
> groovy methods. Then for static methods we look for...
>
>   META-INF/services/groovy/groovyStaticMethods
>
> So in Camel's case, we write a file called
> META-INF/services/groovy/groovyMethods that contains
> "org.apache.camel.groovy.CamelGroovyMethods" and then hey presto;
> anyone with the camel-groovy jar on their classpath gets nice DSL
> magic.
>
>
> Its a pretty trivial patch - and is really easy to back-out if there's
> a better way of doing this. I don't seem to have commit karma any
> more, so I've raised a JIRA and attached the patch for review...
> http://jira.codehaus.org/browse/GROOVY-2116
>
> I'm sure there's another way tinkering with the
> MetaClassRegister/MetaClass stuff; I just liked this simple approach
> as its nice and simple & hard to break & is barely any code etc.
>
> Thoughts?
> --
> James
> -------
> http://macstrac.blogspot.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

XPathCategory.groovy (2K) Download Attachment