Loading...

March 8, 2017

Ratpacked: Combine Groovy DSL With RatpackServer Java Configuration

We have several options to define a Ratpack application. We can use a Java syntax to set up the bindings and handlers. Or we can use the very nice Groovy DSL. It turns out we can use both together as well. For example we can define the handlers with the Groovy DSL and the rest of the application definition is written in Java. To combine both we start with the Java configuration and use the bindings and handlers method of the Groovy.Script class to inject the files with the Groovy DSL.

We start with a sample application where we use Java configuration to set up our Ratpack application:

// File: src/main/java/mrhaki/ratpack/Application.java
package mrhaki.ratpack;

import ratpack.func.Action;
import ratpack.handling.Chain;
import ratpack.handling.Handler;
import ratpack.registry.RegistrySpec;
import ratpack.server.RatpackServer;

import java.util.Optional;

public class Application {

    public static void main(String[] args) throws Exception {
        new Application().startServer();
    }

    void startServer() throws Exception {
        RatpackServer.start(server -> server
                .registryOf(registry())
                .handlers(chain()));
    }

    private Action<RegistrySpec> registry() {
        return registry -> registry
                .add(new RecipeRenderer())
                .add(RecipeRepository.class, new RecipesList());
    }

    private Action<Chain> chain() {
        return chain -> chain.post("recipe", recipeHandler());
    }

    private Handler recipeHandler() {
        return ctx -> ctx
                .parse(RecipeRequest.class)
                .flatMap(recipeRequest -> ctx
                        .get(RecipeRepository.class)
                        .findRecipeByName(recipeRequest.getName()))
                .then((Optional<Recipe> optionalRecipe) -> ctx.render(optionalRecipe));
    }

}

We can use the Groovy DSL for the bindings and handlers definitions and use them in our Java class with the Groovy.Script class. First we create the files bindings.groovy and handlers.groovy in the directory src/main/resources so they will be in the class path of the Java application. We can use the Groovy DSL syntax in the files:

// File: src/main/resources/bindings.groovy
import mrhaki.ratpack.RecipeRenderer
import mrhaki.ratpack.RecipeRepository
import mrhaki.ratpack.RecipesList

import static ratpack.groovy.Groovy.ratpack

ratpack {
    bindings {
        add new RecipeRenderer()
        add RecipeRepository, new RecipesList()
    }   
}
// File: src/main/resources/handlers.groovy
import mrhaki.ratpack.Recipe
import mrhaki.ratpack.RecipeRepository
import mrhaki.ratpack.RecipeRequest

import static ratpack.groovy.Groovy.ratpack

ratpack {
    handlers {
        post('recipe') { RecipeRepository recipeRepository ->
            parse(RecipeRequest)
                    .flatMap { RecipeRequest recipeRequest -> 
                        recipeRepository.findRecipeByName(recipeRequest.name) 
                    }
                    .then { Optional<Recipe> optionalRecipe -> 
                        render(optionalRecipe) 
                    }
        }
    }
}

We have our Groovy DSL files with the definitions. To use them in our Java code to define the Ratpack application we must make sure Ratpack can find them. Therefore we create an empty marker file .ratpack in src/main/resources. With this file in place we can use Ratpack's findBaseDir method to set the base directory for finding external files. It is time to refactor our application:

// File: src/main/java/mrhaki/ratpack/Application.java
package mrhaki.ratpack;

import ratpack.func.Action;
import ratpack.groovy.Groovy;
import ratpack.handling.Chain;
import ratpack.handling.Handler;
import ratpack.registry.RegistrySpec;
import ratpack.server.RatpackServer;

import java.util.Optional;

public class Application {

    public static void main(String[] args) throws Exception {
        new Application().startServer();
    }

    void startServer() throws Exception {
        RatpackServer.start(server -> server
                // Set base dir with directory that
                // contains marker file .ratpack.
                .serverConfig(config -> config.findBaseDir())
                // Use bindings.groovy with static compilation.
                .registry(Groovy.Script.bindings(true))
                // Use handlers.groovy with static compilation.
                .handler(Groovy.Script.handlers(true)));
    }

}

Written with Ratpack 1.4.5.