Search code examples
gradlegroovythymeleafratpackshadowjar

Ratpack + Thymeleaf + shadowJar - Error resolving template "home", template might not exist or might not be accessible


I'm working on ratpack.io web app and using gradle as the build tool. Templates are rendered from template files in a src/main/thymeleaf directory, which works fine at runtime (just using gradle run).

$ ls ./src/main/thymeleaf
home.html

I'm running into issues when I'm creating the uber jar, where the template files aren't included. When I crack open the output jar file I see the thymeleaf directory is empty.

I know part of the shadow-jar process is merging all the dependencies into one jar, but I'm not sure what I need to do include the template files as well. I tried creating special rules to include the html files, but I ended up getting just html files in the jar and not even the ones from the thymeleaf directory.

  • what do I need to configure to get the template files included in this uber jar?
  • if I actually get the files included in the jar's template dir, do I need to update the template resolver to pull the files from the jar vs the current working directory?

Solution

  • Is there any reason you keep your template files in src/main/thymeleaf? By default Thymeleaf templates should be stored in src/ratpack/thymeleaf directory.

    ThymeleafModule class defines a folder name where all templates are stored. The default value is thymeleaf and when you create a shadowJar then you should find a folder thymeleaf right in the JAR archive. shadowJar copies src/ratpack/thymeleaf to this destination without any problem.

    Java based Ratpack project is not aware of src/ratpack by default, but you can easily configure it by creating an empty file called .ratpack in src/ratpack and configuring server -> server.findBaseDir() (more detailed example below).

    Here is a simple example:

    build.gradle

    buildscript {
        repositories {
            jcenter()
        }
        dependencies {
            classpath "io.ratpack:ratpack-gradle:1.5.4"
            classpath "com.github.jengelman.gradle.plugins:shadow:1.2.4"
        }
    }
    
    apply plugin: "io.ratpack.ratpack-java"
    apply plugin: "com.github.johnrengelman.shadow"
    apply plugin: "idea"
    apply plugin: "eclipse"
    
    mainClassName = 'app.RatpackApp'
    
    repositories {
        jcenter()
    }
    
    dependencies {
        // Default SLF4J binding.  Note that this is a blocking implementation.
        // See here for a non blocking appender http://logging.apache.org/log4j/2.x/manual/async.html
        runtime 'org.slf4j:slf4j-simple:1.7.25'
    
        compile ratpack.dependency('thymeleaf')
        compile ratpack.dependency('guice')
    
        testCompile "org.spockframework:spock-core:1.0-groovy-2.4"
    }
    

    src/main/java/app/RatpackApp.java

    package app;
    
    import ratpack.guice.Guice;
    import ratpack.server.BaseDir;
    import ratpack.server.RatpackServer;
    import ratpack.thymeleaf.ThymeleafModule;
    
    import java.util.HashMap;
    
    import static ratpack.thymeleaf.Template.thymeleafTemplate;
    
    public final class RatpackApp {
    
        public static void main(String[] args) throws Exception {
    
            RatpackServer.start(server ->
                    server.serverConfig(config -> config.findBaseDir())
                            .registry(Guice.registry(bindings -> bindings.module(ThymeleafModule.class)))
                            .handlers(chain -> chain.get(ctx -> ctx.render(thymeleafTemplate(new HashMap<String, Object>() {{
                                put("title", "Hello, Ratpack!");
                                put("header", "Hello, Ratpack!");
                                put("text", "This template got rendered using Thymeleaf");
                            }}, "home"))))
            );
        }
    }
    

    src/ratpack/thymeleaf/home.html

    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
    <head>
        <title th:text="${title}" />
    </head>
    <body>
        <h1 th:text="${header}"></h1>
        <p th:text="${text}" />
    </body>
    </html>
    

    Remember to create an empty file .ratpack in src/ratpack so Ratpack can discover this location as a files base dir.

    Now after creating a final JAR with gradle shadowJar I can see the template file being copied correctly:

    ratpack-thymeleaf-example [master●●] % unzip -l build/libs/ratpack-thymeleaf-example-all.jar | grep home
          232  06-24-2018 10:12   thymeleaf/home.html
    

    Here you can find the full example - https://github.com/wololock/ratpack-thymeleaf-example