Skip to content

Latest commit

 

History

History
436 lines (336 loc) · 14.9 KB

README.adoc

File metadata and controls

436 lines (336 loc) · 14.9 KB

jOOQ Codegen Plugin

Overview

Actions Status SonarCloud

A Gradle plugin for working with the jOOQ code generation tool that supports the Gradle Kotlin DSL.

This project started as a Kotlin port of the Groovy-based gradle-jooq-plugin and was initially developed because it was decided that the Groovy plugin would not add Kotlin DSL support.

Tested with jOOQ versions 3.10, 3.11, 3.12 and 3.13 (Open Source and Pro editions) on Java 1.8, 11 and 13, and with Gradle 5+.

Using the plugin

The plugin id needs to be added to the plugins block in the build.gradle.kts file in order to be used.

plugins {
    id("dev.bombinating.jooq-codegen") version "1.7.0"
}

Setting the code generation classpath

The JDBC driver for introspecting the database must be provided in the dependencies block using the jooqRuntime scope, which is created by the plugin. For example:

dependencies {
    jooqRuntime(group = "org.postgresql", name = "postgresql", version = "42.2.6")
}

Using the extension

The plugin defines an extension, jooq, which (optionally) allows both the version and edition of the jOOQ code generation library to be defined, as well as information about the code generation itself.

If the edition or version is not specified, they default to OpenSource and 3.13.0, respectively.

The code generation properties (logging, onError, jdbc and generator) come from the jOOQ code generation Configuration class (from the jOOQ codegen XSD). The plugin provides extension methods to define the properties in a "closure" style.

Finally, the plugin provides two additional properties, runConfig and resultHandler, that can be used to configure the JVM the jOOQ code generation process is run in and to provide a handler for termination of the JVM the code generation was run in, respectively.

Property

Description

Example

edition

jOOQ edition to use (OpenSource, Pro, ProJava8, ProJava6)

JooqEdition.Pro

version

jOOQ version to use

3.13.0

logging

jOOQ code generation config logging setting

Logging.TRACE

onError

jOOQ error configuration

OnError.LOG

jdbc

jOOQ code generation config jdbc settings`

jooq {
    url = ...
    user = ...
    password = ...
    ...
}

generator

jOOQ code generation config generator settings`

generator {
    database {
        ...
    }
    target {
        ...
    }
    ...
}

runConfig

JVM config for running the jOOQ GenerationTool

runConfig { …​ }

resultHandler

Result handler for result for running jOOQ GenerationTool

resultHandler { …​ }

Default task

The plugin also defines a task, jooq, which invokes the jOOQ code generation functionality using the configuration in the jooq extension block.

$ ./gradlew jooq

There are no dependencies on this task and this task does not have any dependencies on other tasks. Therefore, after running the jooq task, it is necessary to run the build task. It is also necessary to add the directory into which the code is being generated into the source set.

Creating tasks

To define additional jOOQ code generation configurations, register/create tasks of type JooqTask.

The JooqTask has the same six code generation-related properties as the jOOQ extension. The jOOQ edition and version properties are not available in the task.

Property

Description

Example

logging

jOOQ code generation config logging setting

Logging.TRACE

onError

jOOQ error configuration

OnError.LOG

jdbc

jOOQ code generation config jdbc settings`

jooq {
    url = ...
    user = ...
    password = ...
    ...
}

generator

jOOQ code generation config generator settings`

generator {
    database {
        ...
    }
    target {
        ...
    }
    ...
}

runConfig

JVM config for running the jOOQ GenerationTool

runConfig { …​ }

resultHandler

Result handler for result for running jOOQ GenerationTool

resultHandler { …​ }

For example:

import dev.bombinating.gradle.jooq.*
...
tasks.register<JooqTask>("jooqAccounting") {
    jdbc {
        ...
    }
    generator {
        ...
    }
    logging = ...
}

This task can be invoked like any other Gradle task:

$ ./gradlew jooqAccounting

Logging

The plugin configures SLF4J and Logback as the logging library for the plugin and provides a default logback.xml file that specifies the log format for the code generation.

To provide a different Logback configuration, add the directory containing the logback.xml file to the jooqRuntime configuration. For example:

jooqRuntime(files("..."))

Properties

The plugin will pass jOOQ-related codegen properties to the code generation process.

Using the jOOQ extension (which defines a task with the name jooq), properties that start with jooq. are passed to the generation tool.

For other jOOQ tasks (i.e, ones that aren’t named jooq), properties of the form <task name>.jooq. are passed to the generation tool with the <task name>. removed (e.g., for a task called accounting, the property accounting.jooq.codegen.jdbc.url would be passed to the code generator as jooq.codegen.jdbc.url).

Use with the Spring Boot and Spring Dependency Management Plugins

The Spring Boot Plugin uses the Spring Dependency Management Plugin to manage dependencies. The jOOQ library is one of the dependencies that the Spring Boot plugin manages. If the Spring Dependency Management Plugin is detected, the jOOQ plugin will set the ext["jooq.version"] value based on the value configured in the jOOQ plugin.

Differences from the original plugin

  • In this plugin, the jooq extension defines a single jOOQ code generation task called jooq. Other jOOQ code generation tasks are explicitly defined using the Gradle task mechanism rather than being implicitly created in the jooq extension block. For example:

...
tasks.register<JooqTask>("...") {
    jdbc {
        ...
    }
    generator {
        ...
    }
    ...
}
...
  • This plugin does not create a task dependency between the jOOQ code generation and the Java compilation task. Instead, if desired, the dependency can be set up explicitly in Gradle.

...
tasks.getByName("compileJava").dependsOn(tasks.getByName("jooq"))
...

Internals

Overview

The plugin works by generating a jOOQ XML configuration file and then invoking the GenerationTool class on it.

Tests

There are four types of tests for the plugin:

  • testing that the extension methods create the correct Configuration object

  • testing that the plugin works with the H2 database

  • testing that the plugin works with PostgreSQL

  • testing that the plugin works with SQL Server

For the PostgreSQL and SQL Server databases, the tests use the Test Containers library to run the databases in a Docker container.

By default, the tests requiring Docker are disabled. To enable them, set the JOOQ_CONTAINER_TESTS environment variable to true.

By default, only the Open Source version of jOOQ is tested. In order to also test the Pro version, set the JOOQ_PRO_TEST environment to true (this will test both the Pro and Pro Java 8 versions). In addition, the JOOQ_REPO_URL, JOOQ_REPO_USERNAME and JOOQ_REPO_PASSWORD environment variables also need to be specified in order for the tests to find the jOOQ Pro artifacts.

In order to run the SQL Server tests (since they require both a Docker container and the Pro version of jOOQ), the JOOQ_CONTAINER_TESTS and JOOQ_PRO_TEST environment variables must be set to true and the JOOQ_REPO_URL, JOOQ_REPO_USERNAME and JOOQ_REPO_PASSWORD must also be specified.

Releasing

To push to a local Maven repository:

$ ./gradlew clean build publishToMavenLocal

To push a snapshot to Artifactory:

$ ./gradlew clean build artifactoryPublish -PbintrayUser=... -PbintrayKey=...

To create a release and create a tag in git for it:

$ ./gradlew clean build release

To push a release to bintray:

$ ./gradlew clean build bintrayUpload -PbintrayUser=... -PbintrayKey=...

To push a release to the Gradle plugin repository:

$ ./gradlew clean build publishPlugins -Pgradle.publish.key=... -Pgradle.publish.secret=...

Appendix A: Minimal Example

In this example, a variable, genDir, is defined for the directory the code will be generated into, and this directory is added to the "main" sourceSets and also used in the target jOOQ configuration.

The database connection info comes from a properties file or from Gradle -P commandline arguments.

import dev.bombinating.gradle.jooq.*

val genDir = "$projectDir/generated/src/main/java"
val jooqUrl: String by project
val jooqUsername: String by project
val jooqPassword: String by project

plugins {
    java
    id("dev.bombinating.jooq-codegen") version "1.7.0"
}

sourceSets["main"].java {
    srcDir(genDir)
}

repositories {
    mavenLocal()
    mavenCentral()
}

dependencies {
    compile(group = "org.jooq", name = "jooq", version = "3.13.0")
    jooqRuntime(group = "org.postgresql", name = "postgresql", version = "42.2.8")
}

jooq {
    jdbc {
        url = jooqUrl
        username = jooqUsername
        password = jooqPassword
    }
    generator {
        database {
            inputSchema = "public"
        }
        target {
            directory = genDir
            packageName = "com.acme.domain.db"
        }
    }
}

The jOOQ code generation, and subsequent build, can be invoked as:

$ ./gradlew clean jooq build

Appendix B: Fuller Example

The first half of this example is the same as above, except:

  • the jOOQ edition is specified (ProJava8)

  • the jOOQ version is specified (3.13.0)

  • the JVM config for running the code generation tool is specified (-Xmx2g)

  • a result handler prints the exit value of the code generation tool

  • the code generation logging is specified (DEBUG)

In addition, an explicit jOOQ task called accounting is defined. This is associated with an Oracle database; like the configuration defined in the jooq extension, the connection info is specified using the Gradle by project construction and read from a properties file or from the commandline. The example also shows a more sophisticated jOOQ configuration.

Finally, the Java compilation is set to depend on the jOOQ code generation for both the jooq and accounting tasks.

import dev.bombinating.gradle.jooq.*
import org.jooq.meta.jaxb.Logging

val genDir = "$projectDir/generated/src/main/java"
val jooqUrl: String by project
val jooqUsername: String by project
val jooqPassword: String by project

val oracleUrl: String by project
val oracleUsername: String by project
val oraclePassword: String by project
val oracleSchema: String by project

plugins {
    java
    id("dev.bombinating.jooq-codegen") version "1.7.0"
}

sourceSets["main"].java {
    srcDir(genDir)
}

repositories {
    mavenLocal()
    mavenCentral()
}

dependencies {
    compile(group = "org.jooq", name = "jooq", version = "3.13.0")
    jooqRuntime(group = "org.postgresql", name = "postgresql", version = "42.2.8")
    jooqRuntime(group = "com.oracle.ojdbc", name = "ojdbc8", version = "19.3.0.0")
}

jooq {
    edition = JooqEdition.ProJava8
    version = "3.13.0"
    runConfig { jvmArgs = listOf("-Xmx2g") }
    resultHandler { println("The exit value of the code generation was: $exitValue") }
    logging = Logging.DEBUG
    jdbc {
        url = jooqUrl
        username = jooqUsername
        password = jooqPassword
    }
    generator {
        database {
            inputSchema = "public"
        }
        target {
            directory = genDir
            packageName = "com.acme.domain.db.pg"
        }
    }
}

val accounting = tasks.register("accounting") {
    jdbc {
        driver = "oracle.jdbc.driver.OracleDriver"
        url = oracleUrl
        username = oracleUsername
        password = oraclePassword
        schema = oracleSchema
    }
    generator {
        generate {
            isJavaTimeTypes = true
        }
        database {
            name = "org.jooq.meta.oracle.OracleDatabase"
            includes = ".*"
            excludes = "^BIN\\$.*|flyway_schema_history"
            inputSchema = oracleSchema
            forcedTypes {
                forcedType {
                    name = "BOOLEAN"
                    expression = ".*_IND"
                    types = ".*"
                }
            }
        }
        target {
            directory = genDir
            packageName = "com.acme.domain.db.oracle"
        }
    }
    logging = Logging.DEBUG
}

tasks.getByName("compileJava").dependsOn(jooq2, tasks.getByName("jooq"))

To generate the code related to both databases, it is sufficient to simply call the build task since it has a dependency on both the joo and accounting tasks Gradle and will therefore ensure that the the source code has been generated from both databases first.

$ ./gradlew clean build

Appendix C: Example projects

A set of example projects, using both the jooq extension and task with the H2 database, is available here. An example of using the plugin from a Groovy Gradle build is also included.

Change Log