Code Generation Directory

164 views
Skip to first unread message

Kevin Jones

unread,
Jul 8, 2023, 12:59:58 PM7/8/23
to jOOQ User Group
I've setup JOOQ code generation in Gradle using the Kotlin DSL.


The generator works except that I have to use the fully qualified name for the output directory, so


.withTarget(
Target()
.withPackageName("com.knowledgespike.db")
.withDirectory("/users/kevinj/projects/thisproject/src/main/generated/kotlin")

)


works, but


.withTarget(
Target()
.withPackageName("com.knowledgespike.db")
.withDirectory("src/main/generated/kotlin")
)


doesn't


If I set the baseDirectory on the configuration object that also works (i.e. I get the code generated relative to the base directory).


What I'd like is to get the code generated in my current project directory.


I can call .withBasedir("$projectDir") but that doesn't feel right to me. Should this "just work"?


Thanks,


Kevin Jones

Lukas Eder

unread,
Jul 10, 2023, 9:30:08 AM7/10/23
to jooq...@googlegroups.com
Hi Kevin,

jOOQ's code generator doesn't really know *how* you run it. I'm not a Gradle guru myself, but build tools often set base directories in one way or another (e.g. where you run the gradle process isn't the same as where the project resides, or the parent project in case you have modules, etc.) Personally, I never trust my judgement in understanding this behaviour, and instead, always use explicit environment variables, system properties or other well known variables. So, telling jOOQ explicitly what $projectDir means to you, which is a well known, documented variable, does seem quite alright, no? Why wouldn't it be?

See:

Cheers,
Lukas

--
You received this message because you are subscribed to the Google Groups "jOOQ User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jooq-user+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/jooq-user/84785ad5-285c-4ac8-90c9-80658024b233n%40googlegroups.com.

Kevin Jones

unread,
Jul 10, 2023, 12:20:19 PM7/10/23
to jooq...@googlegroups.com
I suppose that looking at examples none of the ones I found for Gradle code generation talked about or showed the need to set the base directory explicitly. Based on that I assumed the base directory was going to be the current project directory, obviously it's not

Kevin



--
Kevin Jones
KnowledgeSpike

Per Lundberg

unread,
Aug 2, 2023, 6:55:17 AM8/2/23
to jooq...@googlegroups.com
Hi Kevin,

Late to the party but I happened to see this thread now in my inbox. We also run our codegen via Gradle, using a custom source set named "codegen". We definitely don't have to specify any fully qualified path names, so this problem seems a bit odd indeed. Here's an excerpt from our build.gradle:

tasks.register( 'createAuditLoggingDbJooqDomainClasses', JavaExec ) {
    mainClass = 'fi.hibox.centre.audit.db.codegen.CreateAuditLoggingDbJooqDomainClasses'
    classpath = sourceSets.codegen.runtimeClasspath

    inputs.files( fileTree( 'src/codegen' ) )
    inputs.files( fileTree( 'src/main' ) )

    args( 'src/generated/java', 'fi.hibox.centre.audit.db.domain' )
    outputs.dir( 'src/generated/java' )
}

(The CreateAuditLoggingDbJooqDomainClasses class is a Java console application which calls the org.jooq.codegen.GenerationTool class to run the code generation. It was convenient for us to wrap this in a Java class so we could take care of launching the Postgres server in a Testcontainer instance, apply DB migrations using Flyway and then run the jOOQ code gen, once the DB is fully up and "ready" with all the tables/etc in place.)

What does your use case look like more in detail, I guess you run this towards a "fixed", existing DB rather than a Docker container? Could you share some of your build.gradle to illustrate how you run the code generation in this case?

Best regards,
Per

From: jooq...@googlegroups.com <jooq...@googlegroups.com> on behalf of Kevin Jones <ke...@knowledgespike.com>
Sent: Monday, July 10, 2023 19:20
To: jooq...@googlegroups.com <jooq...@googlegroups.com>
Subject: Re: Code Generation Directory
 

Kevin Jones

unread,
Aug 3, 2023, 11:23:03 AM8/3/23
to jooq...@googlegroups.com
Hi Per,

thanks for the reply.  In my Gradle build file (it's using kts) I have this

sourceSets {
this.main{
kotlin.srcDir("$buildDir/generated/kotlin")
}
}
tasks.create("generateJOOQ") {
GenerationTool.generate(
Configuration()
.withBasedir("$buildDir")
.withJdbc(
Jdbc()
.withDriver("com.mysql.cj.jdbc.Driver")
.withUrl("jdbc:mysql://localhost:3306/xxx")
.withUser("xxx")
.withPassword("xxx")
)

.withGenerator(
Generator()
.withName("org.jooq.codegen.KotlinGenerator")
.withDatabase(
Database()
.withInputSchema("mySchema")
.withName("org.jooq.meta.mysql.MySQLDatabase")
)
.withGenerate(Generate())

.withTarget(
Target()
.withPackageName("com.knowledgespike.db")
                            .withDirectory("generated/kotlin")
.withClean(true)
)
)
)
}

I have to specify the withBaseDir here otherwise the output is lost (or at least appears to be lost),

Kevin



--
Kevin Jones
KnowledgeSpike

Per Lundberg

unread,
Aug 4, 2023, 4:22:01 AM8/4/23
to jooq...@googlegroups.com
Hi again,

Hmm, that's interesting. You seem to use $buildDir in the kotlin.srcDir specifier as well - what happens if you remove this, does it break similarly?

YMMV, but we opted for an approach where we put the generated code in a source set of its own, like this (Groovy code but I'm sure you can convert it to Kotlin if needed):

sourceSets {
    generated {
        java

        // Adds the production classes from the main source set to the compilation and runtime
        // classpaths of the `generated` source set.
        compileClasspath += sourceSets.main.output
        runtimeClasspath += sourceSets.main.output
    }
}

We then consume it like this from another project (we use a multi-project Gradle build):

dependencies {
    implementationModuleBundle project( ':centre-audit-db-schema' )
    implementationModuleBundle project( path: ':centre-audit-db-schema', configuration: 'generated' )

    // ...
}

You are of course free to do it however way you wish, but I think the main advantages for us with this approach are:
  • Makes it easier to exempt generated code from Checkstyle and/or Spotbugs
  • Makes it much easier to avoid "circular dependencies" between your main source set and the generated code
As for your original problem: what directory does it use when do not specify withBasedir? Or does it (the generate files) go somewhere where you can't even find them? 🙂 I think the current working directory should be $projectDir by default (i.e. the project root), so if you want the files under $buildDir you probably have to specify build/generated/kotlin instead of just generated/kotlin.

If you decide to go with a separate "generated" source set as in my example above, that directory would be "src/generated/java" instead (or in your case, "src/generated/kotlin").


I don't know if these suggestions make it better or worse for you, but hopefully it can serve as an inspiration for you and others who are (like us) struggling with getting the code generation working properly with Gradle. It was clearly quite a bit of work before I got this working properly in our project. Gradle can really be a beast sometimes: it's great when you have it working, and extremely flexible because of its DSL and multi-pass-oriented approach (parsing the Gradle build scripts vs running the parsed tasks). But with great flexibility comes great complexity...

Best regards,
Per

Sent: Thursday, August 3, 2023 18:22

Kevin Jones

unread,
Aug 5, 2023, 3:38:15 AM8/5/23
to jooq...@googlegroups.com
If I don't set the base directory when I create the task the generation seems to fail silently. The task runs OK but there's no output (I do a full search of the disk on my Mac and there's nothing). The generation takes the same time as when output is produced so it's doing something.

If I leave out the  $buildDir from the source set definition that doesn't change anything.

I can also create a new sourceSet, rather than add to the 'main' source set:

sourceSets.create("generated") {
java.srcDir("$buildDir/generated/java")
}
but again if I leave out the $buildDir then it doesn't change anything.

If I call setBuildDir("") in the generate task then the task blows up when I run it (I was wondering if it would use some sort of default),

It's a small application so I think splitting it out into a separate Gradle project would be overkill at the moment but it's definitely something I'll keep in mind for the future.

Thanks again for your time on this,

Kevin 

Per Lundberg

unread,
Aug 7, 2023, 2:57:32 AM8/7/23
to jooq...@googlegroups.com
Aha, I see. This seems really weird. Would be interesting to figure out where the output goes, but I hear you've already given it a fair try.

I understand that the multi-project approach here would be overkill for you, so use whatever makes sense for your use case.

Best regards,
Per

Sent: Saturday, August 5, 2023 10:37

To: jooq...@googlegroups.com <jooq...@googlegroups.com>
Subject: Re: Code Generation Directory
--
You received this message because you are subscribed to the Google Groups "jOOQ User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jooq-user+...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages