Groovy-Eclipse, compile and run are using different classloaders?

March 19, 2011

In an Eclipse Groovy project, the order of compilation is causing Groovy classloader conflicts.

I just manually deleted the compiled Groovy classes, then ran the app. Works. Now I rerun still works. Now add a simple blank line to one of the sources and run. It died. Manually delete the output class files, works again. :-(

Strange I don’t have “rebuild automatically” turned on. Also strange, in the project properties, for builders, only the Java builder is listed.

The console output when I get the error:

Caught: groovy.lang.MissingMethodException: No signature of method: static main.SimpleServerSupport.keepAlive() is applicable for argument types: (main.QuestionServer, java.lang.Long) values: [main.QuestionServer@b32ed4, 60000]
Possible solutions: keepAlive(main.QuestionServer, java.lang.Long)

The following classes appear as argument class and as parameter class, but are defined by different class loader:
main.QuestionServer (defined by ‘groovy.lang.GroovyClassLoader$InnerLoader@16921fd’ and ‘org.codehaus.groovy.tools.RootLoader@42e816′)

If one of the method suggestions matches the method you wanted to call,
then check your class loader setup.
at main.QuestionServer.main(QuestionServer.groovy:72)

Haven’t solved this yet. I can’t find any reference to something like it. Maybe I just have a config issue?

I now remember that the plugin adds hooks into the Java compiler. So is the compiler used different when you run the app with “run as Groovy script” then when Java builder executes, that is what the Classloader names would suggest? But, that makes no sense, since at run time, the classloader hierarchy has nothing to do with the compile, or does it, since Groovy precompiles at runtime?

Yes, I uninstalled the Groovy feature and reinstalled.
Running the same program (script) at the command line is fine.

Todo: Post some code that exhibits the issue. The current code is still at the “throw at wall and see what sticks” stage.

Updates

  • 20110328T2010-5: Solved it. I moved a method from a support class, into the main SimpleServer class. This method was using an Executor.newScheduledThreadPool(1) to start a thread to limit the server’s lifetime, it also did a little console spinner to show that there is something running. I don’t see how that is related to classloaders.

Environment
Windows 7 64bit Professional
Eclipse Helios Service Release 2
Groovy-Eclipse Feature 2.1.3.xx-20110317-1200-e36


Java Dev Using Embedded Groovy Console in Eclipse

December 12, 2010

In development, simple but powerful tools to get at the essence of a code source in order to understand, test, and extend it is essential. This is even more important in Test Driven Development (TDD). Eclipse’s Java Debugger is for most situations, powerful enough. Eclipse has an Expressions View available in the debug perspective to execute snippets of code. The Java Development Toolkit (JDT) also has a Scrapbook facility that allows the creation, storage, and running of experimental code. And, of course, all the other features of the debugger are excellent.

However, when you need it, it’s possible to embed a script engine and have new ways of analyzing and developing code. In listing 1, an app shows the use of the ConsoleWaiter class. When the code executes the waiter.run() at line 43, it opens the Groovy Console which allows the use Groovy shell scripting in a GUI frame, see figure 1. When the console is closed the app continues executing.

Listing 1
/*
* File: ExampleApp2.java
* @author jbetancourt
* Date: 20101213T1718-5
*
*/
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
*
* @author jbetancourt
*
*/
public class ExampleApp2 {
   static public String greeting = "Hello world!";
   private static final List<String> nodes;

   static {
        nodes = new
            ArrayList<String>(
                  Arrays.asList("one","two"));
   }

   private String title = "Example 2";

   public String getTitle(){
      return title;
   }

   /**
   * @param args command line args
   */
   public static void main(String[] args) {
      ExampleApp2 app = new ExampleApp2();

      ConsoleWaiter waiter = new ConsoleWaiter(app);

      waiter.setVar("greet", greeting);
      waiter.setVar("nodes", nodes);
      waiter.setVar("title", app.getTitle());
      waiter.run();
      System.out.println("Done!");
   }

}
screen capture of Groovy console

Console screen capture, click to view

Another screen capture, click to view

This is awesome. In one project I had to examine the contents of a Properties object. Did it have an “email” value? I was stumped when using the Eclipse debugger, it did not show all entries in the Map, at the end was “…”. Sure, I could use the Expressions window, but with the Console I could not only do a get(key), but iterate using Groovy style closures and much more.

The magic that enables this is the ConsoleWaiter.groovy class shown below in listing 2 that was written by John Green. Since a Groovy script is a Java class underneath, in Eclipse you can call Groovy from Java easily (some compiler magic).

Listing 2
/**
 * File:  ConsoleWaiter.groovy
 */

import groovy.lang.Binding;
import groovy.ui.Console;

/**
 * Provides a wrapper for the console.
 *
 * Based on source by John Green
 * Adapted from:  http://www.oehive.org/files/ConsoleWaiter.groovy
 * Released under the Eclipse Public License
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * I added methods to allow use from Java.
 *
 * The run() method launches the console and causes this thread
 * to sleep until the console's window is closed.
 * Allows easy interaction with the objects alive at a given
 * point in an application's execution, like in a debugger
 * session.
 *
 * Example 1:
<pre> * new ConsoleWaiter().run()
 *</pre>
 *

 * Example 2:
<pre> * def waiter = new ConsoleWaiter()
 * waiter.console.setVariable("node", node)
 * waiter.run()
 *</pre>
 */
class ConsoleWaiter {
 Console console
 Object source
 boolean done = false;

 /** */
 public ConsoleWaiter(Console inConsole){
    this.console = inConsole
 }

 /** */
 public ConsoleWaiter(Object source){
    console =
    new Console(getClass().classLoader,
    new Binding())
    this.source = source
    console.setVariable("source", source)
 }

 /** */
 public void setVar(String key, Object value){
    console.setVariable(key, value)
 }

 /** 	 */
 public void setVar(String key, List values){
    console.setVariable(key, values)
 }

 /** 	 */
 public void setVar(String key, Object[] values){
    console.setVariable(key, values)
 }

 /** 	 */
 public void run() {
    console.run()
    // I'm a little surprised that this exit() can be private.
    console.frame.windowClosing = this.&exit
    console.frame.windowClosed = this.&exit
    while (!done) {
       sleep 1000
    }
 }

 /** 	 */
 public boolean isDone(){
    return done;
 }

 /** 	 */
 public void exit(EventObject evt = null) {
    done = true
 }

 /** 	 */
 public Console getConsole(){
    return console;
 }
}

Eclipse Integration

The disadvantage of this approach is that you have to put extraneous code inside the tests or target class. Not only is this tedious and slow, what if code is accidentally deployed like this? A better approach is to just set a breakpoint in the code, and then have the ability to open a script console at that breakpoint, in the Java Stack Frame, that has access to the execution context and classpath. Is there an Eclipse add-in that does this? If not, there should be.

Conclusion

Shown was a simple example of embedding a Groovy console in Java code to allow scripting. Of course, this is not a new idea. It was even mentioned in an older JVM scripting language, Beanshell. Note that it is possible to instead of using a GUI console, to use the Groovy shell, InteractiveShell class. In the reading list below this approach is taken to allow remote scripting of a server hosted application.

Updates

  • Oct 10, 2011:
    Interesting tool that could be relevant: YouDebug.
  • March 20, 2012: Not exactly same scenario, but the concept of an embedded script console is found in many products. Jenkins CI Server has one and it uses Groovy. Jenkins Script Console

Further reading


Follow

Get every new post delivered to your Inbox.