Embed a Groovy Web Console in a Java Spring App

| Comments

Having a web-based Groovy console for your Java Spring webapp can be invaluable for developing and testing. It might also be appropriate for your production app as long as it’s properly secured. The Grails world has long had the Console Plugin and I’ve seen firsthand how useful a console can be on earlier Grails projects.

Not every project I get to work on is in Grails though, but I wanted to have the same power in my Spring/Java applications.

I’ll demonstrate how to integrate this with a REST-based web service, but the same core Service code could be used for other website interaction types.

Gradle Dependency

Because it’s a Groovy console, you’ll obviously need to have the groovy jar loaded as a dependency and included in your war file, but your application code (and the sample Service code below) can all be in Java.

If you’re using gradle, you can add something like this to your build.gradle file:

repositories {

dependencies {
    compile 'org.codehaus.groovy:groovy-all:2.1.8'

If you’re using Maven, you’re on your own :).

Server Side – the RESTful ScriptService

The Service has a script method that you can POST groovy code to and have it execute within the Spring context, and within a Transaction. The Service then captures the stdout output from the script as well as the return value and returns it back to the caller as a Map.

The private createShell method defines the objects that will be made available in the script binding and can be used in your script without any declarations. In mine, I’ve defined:

  • ctx – the Spring application context that you can use to get other Spring beans
  • entityManager – the JPA entity manager that we get from Spring
  • LOG – the script logger that we can use to put stuff in the log

Don’t forget to secure it with some sort of super-user type role!

package com.naleid.console;

import org.springframework.security.access.annotation.Secured;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.Map;

public interface ScriptService {
    Map executeScript(String script);

And the Impl (much of which is converted from the Grails Console Plugin):

package com.naleid.console;

import groovy.lang.Binding;
import groovy.lang.Closure;
import groovy.lang.GroovyShell;
import groovy.ui.SystemOutputInterceptor;
import org.apache.log4j.Logger;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.HashMap;
import java.util.Map;

public class ScriptServiceImpl implements ScriptService {
    private static final Logger LOG = Logger.getLogger(ScriptServiceImpl.class);

    @PersistenceContext(unitName = "yourAppsPersistenceContext")
    protected EntityManager entityManager;

    @Autowired private ApplicationContext applicationContext;

    @Transactional(propagation = Propagation.REQUIRED, readOnly = false)
    public Map executeScript(String script) {
        LOG.warn("Executing Script: " + script);

        try {
            return eval(script);
        } catch (Throwable t) {
            HashMap resultMap = new HashMap();
            resultMap.put("error", t.getMessage());
            return resultMap;

    @Transactional(propagation = Propagation.REQUIRED, readOnly = false)
    protected Map eval(String script) {
        Map resultMap = new HashMap();
        resultMap.put("script", script);
        resultMap.put("startTime", DateTime.now().toString());

        SystemOutputInterceptorClosure outputCollector = new SystemOutputInterceptorClosure(null);
        SystemOutputInterceptor systemOutputInterceptor = new SystemOutputInterceptor(outputCollector);

        try {
            HashMap bindingValues = new HashMap();
            resultMap.put("result", eval(script, bindingValues));
        } catch (Throwable t) {
            resultMap.put("error", t.getMessage());
        } finally {

        resultMap.put("output", outputCollector.getStringBuffer().toString().trim());
        resultMap.put("endTime", DateTime.now().toString());
        return resultMap;

    public String eval(String script, HashMap bindingValues) {
        GroovyShell shell = createShell(bindingValues);
        Object result = shell.evaluate(script);
        String resultString = result != null ? result.toString() : "null";
        LOG.trace("eval() result: " + resultString);
        return resultString;

    private GroovyShell createShell(HashMap bindingValues) {
        bindingValues.put("entityManager", entityManager);
        bindingValues.put("ctx", applicationContext);
        bindingValues.put("LOG", LOG);
        return new GroovyShell(this.getClass().getClassLoader(), new Binding(bindingValues));

// here's where the magic happens allowing the service to capture the output while the script runs
class SystemOutputInterceptorClosure extends Closure {

    StringBuffer stringBuffer = new StringBuffer();

    public SystemOutputInterceptorClosure( Object owner ) {
        super( owner ) ;

    public Object call( Object params ) {
        return false;

    public Object call(Object... args) {
        return false;

    public StringBuffer getStringBuffer() {
        return this.stringBuffer;

Client Side – Browser Console

Now that you have a REST endpoint, you can call it right from the browser (after you’ve authenticated as a user that has rights to hit your endpoint). Here’s a simple script that you could put in the Chrome console to execute and return all of the bean names in your app, it assumes jQuery is being used:

$.ajax({ type: 'POST', contentType:"text/plain; charset=utf-8", data: "ctx.beanDefinitionNames.join('\\n')", url: "http://localhost:8080/rest/script"}).always(function(response, textStatus) { console.log("%o, %o, %o", response, textStatus, response.result) })

It also assumes you’re running on localhost:8080 and that your REST services are found under /rest, edit to taste.

Client Side – Ace Editor UI

Editing a groovy script in the middle of a big JavaScript ajax call is kind of gross, so it’d be better if there were a UI on it that you can interact with.

How you put this in your app will depend a lot on the client side tech that you’re using, but at the very least you’ll want a textarea that you can POST.

Here’s an example of a JavaScript function that you can use to POST your code and then update a passed in model object with fields that can be bound to the view (client side stuff is quite dependent on your client-side tech stack):

submitScript: function(code, model) {
  window.console.log("submitting script %o", code);
  var deferred = $.ajax({ 
    type: 'POST', 
    contentType:"text/plain; charset=utf-8", 
    data: code,
    url: 'http://localhost:8080/rest/script'

  deferred.always(function(response, textStatus) {
    model.set("output", response.output);
    model.set("result", response.result);
    model.set("error", response.error);
    model.set("startTime", response.startTime);
    model.set("endTime", response.endTime);

If you’re not using something like Backbone or Angular, you could instead directly update the view when the response comes back.

If you want to get fancy, I suggest using the Ace Editor as an enhanced textarea. The Ace Editor is a very cool embeddable text editor, it even has a vim mode!

Wrapping Up

This isn’t quite as fully featured as the Grails Console is, but it has all of the core features that you’ll need to get a web-based Groovy console up and running.