Developing with DominoKit with Gradle

Originally posted on 2020-11-04

I migrated all of my projects from Maven to Gradle a few years back. Generally it has been hard but worthwhile to move from XML to something that's slightly easier to extend. In some cases I'm now using the Kotlin DSL but I'm still evaluating whether that was a mistake or not as there are far fewer examples of how to do things with the Kotlin DSL than the Groovy DSL.

In any case I've built up a baseline build.gradle.kts that I am using in a few DominoKit projects.

This configuration gives you a few things:

  • An easy way to run the application in Jetty
./gradlew appRunWar -x compileGwt
  • An easy way to start super dev mode
./gradlew gwtSuperDev
  • A full output JAR file, using Gradle Shadow, that can run inside of AWS Lambda
./gradlew shadowJar

Here's the build.gradle.kts:

import groovy.lang.Closure
import org.akhikhl.gretty.GrettyExtension
import org.wisepersist.gradle.plugins.gwt.GwtCompileOptions
import org.wisepersist.gradle.plugins.gwt.GwtPluginExtension
import org.wisepersist.gradle.plugins.gwt.GwtSuperDevOptions
import org.wisepersist.gradle.plugins.gwt.Style

plugins {
    kotlin("jvm") version "1.4.10"
    id("application")
    id("java")
    id("idea")
    id("java-library")
    id("war")

    // Creates fat JAR
    id("com.github.johnrengelman.shadow") version "6.0.0"

    id("org.wisepersist.gwt") version "1.1.9"
    id("org.gretty") version "3.0.3"
}

java.toolchain.languageVersion.set(JavaLanguageVersion.of(8))

// Required if using DominoMVP and annotations that generate code
sourceSets {
    val main by getting
    main.java.srcDirs("build/generated/sources/annotationProcessor/java/main")
}

// Required for shadow JAR but we don't use it. Can not be replaced with application.mainClass.set.
application.mainClassName = "not-necessary"

val gradleDependencyVersion = "6.7.1"

tasks.wrapper {
    gradleVersion = gradleDependencyVersion
    distributionType = Wrapper.DistributionType.ALL
}

repositories {
    mavenCentral()
    // Required for gretty
    maven(url = "https://repo.spring.io/plugins-release/")
    // Required for Domino UI
    maven(url = "https://oss.sonatype.org/content/repositories/snapshots")
    // Required for Domino UI
    maven(url = "https://repo.vertispan.com/gwt-snapshot/")
}

tasks.distZip { enabled = false }
tasks.distTar { enabled = false }
tasks.shadowDistZip { enabled = false }
tasks.shadowDistTar { enabled = false }

val gwtServletVersion = "2.9.0"
val junitVersion = "4.13"
val jettyVersion = "9.4.32.v20200930"
val gsonVersion = "2.8.6"
val dominoKitVersion = "1.0-SNAPSHOT"
val dominoKitApiVersion1 = "1.0-rc.4-SNAPSHOT"
val dominoKitApiVersion2 = "1.0-rc.5-SNAPSHOT"

dependencies {
    implementation("com.google.gwt:gwt-servlet:$gwtServletVersion")
    implementation("org.eclipse.jetty:jetty-servlet:$jettyVersion")
    implementation("org.eclipse.jetty:jetty-server:$jettyVersion")
    implementation("com.google.code.gson:gson:$gsonVersion")

    // 1.0-SNAPSHOT
    api("org.dominokit:domino-ui:$dominoKitVersion") { setChanging(true) }
    api("org.dominokit:domino-ui-map-addon:$dominoKitVersion") { setChanging(true) }

    // 1.0-rc.4-SNAPSHOT
    api("org.dominokit:domino-rest-gwt:$dominoKitApiVersion1") { setChanging(true) }
    annotationProcessor("org.dominokit:domino-rest-apt:$dominoKitApiVersion1") { setChanging(true) }

    // 1.0-rc.5-SNAPSHOT
    api("org.dominokit.domino:domino-gwt-view:$dominoKitApiVersion2") { setChanging(true) }
    annotationProcessor("org.dominokit.domino.apt:apt-client:$dominoKitApiVersion2") { setChanging(true) }
}

configurations.all {
    // Check for updates on changing dependencies at most every 10 minutes
    resolutionStrategy.cacheChangingModulesFor(10, TimeUnit.MINUTES)
}

configurations.compile {
    // Fixes - Caused by: java.util.ServiceConfigurationError: org.apache.juli.logging.Log: org.eclipse.jetty.apache.jsp.JuliLog not a subtype
    exclude("org.mortbay.jasper")
}

// Extension configuration
configure<GrettyExtension> {
    // Supported values:
    // "jetty7", "jetty8", "jetty9", "tomcat7", "tomcat8"
    servletContainer = "jetty9.4"
}

configure<GwtPluginExtension> {
    gwtVersion = "2.9.0"
    maxHeapSize = "2048M"

    modules("modulename.App")
    devModules("modulename.AppDev")

    compiler(closureOf<GwtCompileOptions> {
        localWorkers = 8
        optimize = 9
        maxHeapSize = "2048M"
        // Set this value if you need to debug the generated source
        // style = Style.PRETTY
    } as Closure<GwtCompileOptions>)

    superDev(closureOf<GwtSuperDevOptions> {
        noPrecompile = true
        maxHeapSize = "2048M"
    } as Closure<GwtSuperDevOptions>)
}

// Task configuration
tasks.war {
    // Make sure GWT code is compiled before the war is generated1
    dependsOn += tasks.compileGwt
}

tasks.shadowJar {
    // Wait until the war is generated so we can get the files from its output directory
    dependsOn += tasks.war
    dependsOn += tasks.warTemplate

    // Get all of the GWT compiler output
    from("build/gwt/out")

    // Get all of the static assets
    from("war")

    // Exclude WEB-INF so we don't include a bunch of classes we don't need
    exclude("WEB-INF")

    dependencies {
        // NOTE: Do not exclude the following dependencies or things will break
        // - javax.servlet:.*
        // - com.google.gwt:gwt-servlet:.*
        exclude(dependency("org.gwtproject.i18n:.*"))
        exclude(dependency("org.gwtproject.core:.*"))
        exclude(dependency("org.gwtproject.editor:.*"))
        exclude(dependency("org.gwtproject.timer:.*"))
        exclude(dependency("org.gwtproject.event:.*"))
        exclude(dependency("org.gwtproject.safehtml:.*"))
        exclude(dependency("org.dominokit:.*"))
        exclude(dependency("io.vertx:.*"))
        exclude(dependency("net.sourceforge.htmlunit:.*"))
        exclude(dependency("colt:.*"))
        exclude(dependency("com.github.tdesjardins:.*"))
        exclude(dependency("tapestry:.*"))
        exclude(dependency("com.google.gwt:gwt-dev:.*"))
        exclude(dependency("com.google.gwt:gwt-user:.*"))
        exclude(dependency("net.sourceforge.cssparser:.*"))
        exclude(dependency("com.ibm.icu:.*"))
        exclude(dependency("javax.websocket:.*"))
        exclude(dependency("org.glassfish:.*"))
    }
}