All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dev.monosoul.jooq.codegen.ReflectiveJooqCodegenRunner.kt Maven / Gradle / Ivy

There is a newer version: 6.1.14
Show newest version
package dev.monosoul.jooq.codegen

import org.jooq.codegen.GenerationTool
import org.jooq.meta.jaxb.Configuration
import org.jooq.meta.jaxb.Strategy
import org.jooq.util.jaxb.tools.MiniJAXB
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.InputStream
import kotlin.reflect.jvm.jvmName

internal class ReflectiveJooqCodegenRunner(
    codegenAwareClassLoader: ClassLoader,
) : JooqCodegenRunner {
    private val codeGenTool =
        ReflectiveGenerationTool(codegenAwareClassLoader).apply {
            setClassLoader(codegenAwareClassLoader)
        }

    override fun generateJooqClasses(configuration: Configuration) = codeGenTool.run(configuration)

    /**
     * Wrapper for jOOQ code generation tool object obtained via reflection.
     * @see GenerationTool
     */
    private class ReflectiveGenerationTool(codegenAwareClassLoader: ClassLoader) {
        private val toolClass = codegenAwareClassLoader.loadClass(GenerationTool::class.jvmName)
        private val configurationClass = codegenAwareClassLoader.loadClass(Configuration::class.jvmName)
        private val tool = toolClass.getDeclaredConstructor().newInstance()

        /**
         * @see GenerationTool.setClassLoader
         */
        fun setClassLoader(classLoader: ClassLoader) {
            val setClassLoaderMethod =
                toolClass.getDeclaredMethod(
                    GenerationTool::setClassLoader.name,
                    ClassLoader::class.java,
                )
            setClassLoaderMethod.invoke(tool, classLoader)
        }

        /**
         * @see GenerationTool.run
         */
        fun run(configuration: Configuration) {
            val preparedConfiguration = load(configuration.sanitize().toXmlByteArray())
            val runMethod = toolClass.getMethod(GenerationTool::run.name, configurationClass)
            runMethod.invoke(tool, preparedConfiguration)
        }

        private fun Configuration.sanitize() =
            apply {
                // [#100] MiniJAXB class provided by jOOQ doesn't respect default value of XmlElement
                // It serializes the value even if it's the same as the default value
                generator?.strategy?.also {
                    if (it.name == defaultGeneratorStrategyName) {
                        it.name = null
                    }
                }
            }

        private fun Configuration.toXmlByteArray() =
            ByteArrayOutputStream().also { stream ->
                stream.writer().use { writer ->
                    @Suppress("UnstableApiUsage")
                    MiniJAXB.marshal(this, writer)
                    writer.flush()
                }
            }.toByteArray()

        /**
         * @see GenerationTool.load
         */
        private fun load(xmlByteArray: ByteArray): Any {
            val loadMethod = toolClass.getMethod(GenerationTool::load.name, InputStream::class.java)
            return ByteArrayInputStream(xmlByteArray).use {
                loadMethod.invoke(null, it)
            }
        }

        private companion object {
            val defaultGeneratorStrategyName: String? = Strategy().name
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy