Running Groovy on the NetBeans Platform

Here's a Groovy POJO:

package org.my.app

public class DemoPojo {

    def foo
	
}

And here's my ModuleInstall class (which is a NetBeans module's lifecycle manager), which uses its restored() method to instantiate the POJO, set the variable, and then print out the variable. Oh, by the way, the class below is, just like the above, a Groovy class. The thing to notice is that I defined no getter/setter in the POJO above, because Groovy simply assumes I have them, and that there are no semi-colons at the end of the statements at all (thanks again Groovy).

package org.my.app

import org.openide.modules.ModuleInstall as MI

public class Installer extends MI {

    @Override
    public void restored() {

        for(int i = 0; i < 10; i++) {
            DemoPojo dp = new DemoPojo()
            dp.setFoo(i)
            println("Number: " + dp.getFoo())
        }

    }
    
}

Also, the "println" statement comes from Groovy, without my needing to import the class. Look also at the abbreviation for my imported class, which I can then refer to in that way in my class signature (and anywhere else). In fact, I could use any Groovy constructs at all now.

So the above two are in a module. The ModuleInstall class is registered in the Manifest, just like any other ModuleInstall class, because after compilation the Groovy class becomes a Java class. At that point, there's no difference anymore.

To make all of the above possible, add the following to your module's build.xml file:

<taskdef name="groovyc"
     classpath="ext/groovy-all.jar"
     classname="org.codehaus.groovy.ant.Groovyc"/>

<target name="netbeans-extra">
    <groovyc srcdir="${src.dir}" destdir="${build.classes.dir}">
        <classpath refid="cp"/>
    </groovyc>
    <jarwithmoduleattributes jarfile="${cluster}/${module.jar}"
           compress="${build.package.compress}" index="${build.package.index}"
           manifest="${manifest.mf}" stamp="${cluster}/.lastModified">
        <fileset dir="${build.classes.dir}"/>
    </jarwithmoduleattributes>
</target>

So, after the Groovy compiler does its thing, the module's JAR is recreated, using the output from the Groovy compiler. Note that, as indicated above, you need a folder in your module named "ext", containing "groovy-all.jar". You also need to put your module in a suite and set a dependency on a library wrapper module that contains "groovy-all.jar".

Here's the Projects view on my module, isn't it cool to see only Groovy classes there?

Then you've got everything you need to run Groovy on the NetBeans Platform. Now excuse me while I go and create some file templates for Groovy versions of TopComponents, Actions, and so on...

Comments:

Unfortunately Groovy for Platform development becomes less appealing with NB 7.0 because groovyc does not seem to support JSR 269 - or at least gmaven-plugin does not support it, and nothing on the Groovy site indicates that it is even planned. Which means that any objects you want to register declaratively must either be written in Java or registered the old way in the XML layer.

Posted by Jesse Glick on February 13, 2009 at 02:45 AM PST #

Well, what's so wrong with using the XML layer? If that's the only downside, then that's not so bad at all. The real downside is joint compilation between Java and Groovy. My approach above assumes that everything is Groovy classes. Well, I don't see what's wrong with that. But, add one Java class and this solution fails.

Posted by Geertjan on February 13, 2009 at 04:16 AM PST #

So what about doing the same using jython? Anyone any experience?

Posted by Sven Reimers on February 13, 2009 at 06:59 PM PST #

Good question. All you need is an Ant target like the one I show above for Groovy. That's all it would (should) take.

Posted by Geertjan on February 13, 2009 at 09:46 PM PST #

Jesse, where is a good sample of registering an object declaratively using Java?

Posted by Paul King on February 14, 2009 at 06:22 PM PST #

Here's one:
http://blogs.sun.com/geertjan/entry/org_openide_util_lookup_serviceprovider

Posted by Geertjan Wielenga on February 14, 2009 at 06:27 PM PST #

Re: Only Groovy files ...

Just added "&lt;javac includes="\*.java"/&gt;" inside the groovyc task as well a Doubler Java class and changed restored() method in Installer

5.times { int i ->
int j = Doubler.twice(i)
def dp = new DemoPojo(foo:j)
println "Number: " + dp.foo
}

Seemed to work fine unless Netbeans was doing something special and compiling Doubler under the covers.

Posted by Paul King on February 14, 2009 at 06:48 PM PST #

Awesome!!! Going to try that right away.

Posted by Geertjan Wielenga on February 14, 2009 at 06:51 PM PST #

Yup, your example works for me. The Ant target needs to be tweaked exactly as you have it. Java and Groovy integration on the NetBeans Platform. How cool is that.

Posted by Geertjan Wielenga on February 14, 2009 at 07:10 PM PST #

Re: annotations and Groovy files ...

See this screenshot, which is quite interesting:
http://blogs.sun.com/geertjan/resource/groovy-warning-sprovider.png

Posted by Geertjan Wielenga on February 14, 2009 at 07:42 PM PST #

The error message is partially obscuring the next line but it looks as if the next line might be an inner class which isn't supported until Groovy 1.7 (there are usually better ways, e.g. closures, to do inner classes in Groovy). Perhaps the example needs some restructuring.

Groovy doesn't have explicit JSR 269 support but given that it calls javac under the covers for joint compilation (gmaven I am less clear on) perhaps there is some stuff that can be easily made to (already does?) work.

Posted by Paul King on February 15, 2009 at 06:04 AM PST #

Using a Groovy installer class and a restore() method like:

Lookup.default.lookupAll(DemoInterface).each {
di -> println "Hello from Groovy: " + di.name
}

seems to allows hooking into JSR269 services without issues. At the moment you would still need to write the actual service in Java but it seems to happily all sit together using the previous mod to the build file for enacting the joint compiler.

Posted by Paul King on February 16, 2009 at 07:59 PM PST #

The screenshot is off base. You can indeed annotate Groovy classes - I tried - and you can even read runtime annotations using reflection. And of course you can look up services from Groovy code. What you cannot do, as Paul King just said, is write the service in Groovy: the annotation will be accepted by groovyc but there is no META-INF/services/org.demoservice.DemoInterface file generated as a result.

Since more and more NetBeans SPIs are being migrated to the use of annotations for their registration, Groovy cannot be a full replacement for Java in such modules - unless you manually create old-style XML layer entries, which is also becoming more difficult to do as more advanced lazy loading strategies are implemented.

It would be great if Groovy's compiler could support JSR 269. While the JSR of course does not define a source language exactly like Groovy, in practice most of javax.lang.model.\*\* would fit Groovy pretty well (since it is designed to compile into more or less "natural" JVM classes). Indeed, if mixed compilation is accomplished simply by generating \*.java from Groovy sources, as the Maven plugin seems to do, then it would seem straightforward to run annotation processors, though mapping Filer messages back to original \*.groovy sources could be tricky.

Posted by Jesse Glick on February 17, 2009 at 01:08 AM PST #

@Jesse: yes, that summaries it well. No promises, but there is now an issue to track this in Groovy's Jira:

http://jira.codehaus.org/browse/GROOVY-3361

If you can think of any suggestions for getting the ball rolling or good standalone examples that can act as a driver, please feel free to add comments to the issue.

Posted by Paul King on February 17, 2009 at 06:47 AM PST #

Great, i searched a long time for this. Maybe someone can update this open issue now.

http://www.netbeans.org/issues/show_bug.cgi?id=129812

Posted by anonymous on February 27, 2009 at 07:54 PM PST #

Hello Geertjan,

I was wondering if you could maybe explain this section of the instructions more.

"So, after the Groovy compiler does its thing, the module's JAR is recreated, using the output from the Groovy compiler. Note that, as indicated above, you need a folder in your module named "ext", containing "groovy-all.jar". You also need to put your module in a suite and set a dependency on a library wrapper module that contains "groovy-all.jar"."

If you have a groovy-all module that has the 'groovy-all.jar' in it and you have the other module 'Demo' that is dependent on the'groovy-all' module, then why do you have to add groovy-all.jar to your 'Demo' module?

Seems like the Demo module should find the jar file because of the dependency? The only other thing I can think of is that you need the jar locally in 'Demo' for compile time resolution and then the module 'groovy-all' is used at run-time. But that doesn't seem to make sense at all either.

Thanks for you time to explain a bit more. I've got it working by doing what you suggest above in 6.7, but was wondering about why the jar file for groovy is needed in both modules.

Thanks!

Posted by Sam Griffith on July 31, 2009 at 06:17 AM PDT #

Post a Comment:
  • HTML Syntax: NOT allowed
About

Geertjan Wielenga (@geertjanw) is a Principal Product Manager in the Oracle Developer Tools group living & working in Amsterdam. He is a Java technology enthusiast, evangelist, trainer, speaker, and writer. He blogs here daily.

The focus of this blog is mostly on NetBeans (a development tool primarily for Java programmers), with an occasional reference to NetBeans, and sometimes diverging to topics relating to NetBeans. And then there are days when NetBeans is mentioned, just for a change.

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
12
13
14
18
19
21
22
23
24
25
26
27
28
29
30
   
       
Today