使用JOOQ

时间:2017-09-26 14:49:49

标签: java mysql enums jooq

我有下表YNM:

 id  name
 1   YES
 2   NO 
 3   MAYBE

并希望JOOQ生成以下java enum:

public enum YNM {
   YES,NO,MAYBE;
}

据我所知,由于过于复杂/反直觉,因此在JOOQ 3中删除了对此的支持。有没有办法实现这个目标?

提前致谢。

3 个答案:

答案 0 :(得分:3)

我认为您应该可以使用EnumConverter

public class YNMConverter extends EnumConverter<String, YNM > {

    public YNMConverter() {
        super(String.class, YNM.class);
    }
}

然后,您需要将其作为自定义类型和强制类型添加到codegen。这是一个程序化的例子

new CustomType()
.withName("YNM")
.withType(YNM.class.getName())
.withConverter(YNMConverter.class.getName());

new ForcedType()
.withTypes("varchar")
.withName("YNM")
.withExpression(".*ynm.*") // regex to match the column name

您需要将强制类型和自定义类型添加到codegen。这可以在maven / xml或编程中完成

答案 1 :(得分:3)

我知道这是一个老问题,但是我发布了答案,因为它可能对其他人有用。

我必须面对相同的需求,并且很难实现,因此在这里您可以找到我实现的用于从enums模式生成枚举的代码。

该代码是用Groovy实现的,但是对于Java来说却非常相似。

首先,非常重要,我必须为我的枚举生成器创建一个单独的项目,因为它将作为将要使用它的项目的依赖项。 需要,因为生成代码的项目必须在编译时运行枚举生成器,因此实现此目的的方法是将枚举生成器添加为依赖项。

枚举生成器项目依赖项

package com.ctg.jooqgenerator.jooq

import org.jooq.codegen.JavaGenerator
import org.jooq.codegen.JavaWriter
import org.jooq.meta.Database
import org.jooq.meta.SchemaDefinition
import org.jooq.meta.TableDefinition
import org.slf4j.Logger
import org.slf4j.LoggerFactory

import java.sql.ResultSet

class EnumGenerator extends JavaGenerator {
    private static final String ENUMS_SCHEMA = "enums"

    private static final Logger log = LoggerFactory.getLogger(EnumGenerator.class)

    @Override
    void generateSchema(SchemaDefinition schema) {
        // Apply custom logic only for `enums` schema. Others schema has regular generation
        if (schema.name != ENUMS_SCHEMA) {
            super.generateSchema(schema)
            return
        }

        log.info("Generating enums")
        log.info("----------------------------------------------------------")

        Database db = schema.database

        db.getTables(schema).each { TableDefinition table ->
            // Prepare enum name from snake_case to CamelCase
            String enumName = table.name.replaceAll('_([a-z])') { it[1].capitalize() }.capitalize()

            JavaWriter out = newJavaWriter(new File(getFile(schema).getParentFile(), "${enumName}.java"))
            log.info("Generating enum: {}.java [input={}, output={}]", enumName, table.name, enumName)

            printPackage(out, schema)

            out.println("public enum $enumName {")

            ResultSet rs = db.connection.prepareStatement("SELECT * FROM ${schema}.\"${table.name}\"").executeQuery()
            while (rs.next()) {
                String name = rs.getString('name'),
                       description = rs.getString('description'),
                       s = rs.isLast() ? ";" : ","

                // Generate enum entry
                out.tab(1).println("$name(\"$description\")$s")
            }

            out.println("""
            |    private final String description;
            |
            |    private $enumName(String description) {
            |        this.description = description;
            |    }
            |}
            """.stripMargin())

            closeJavaWriter(out)
        }

        log.info("----------------------------------------------------------")
        super.generateSchema(schema)
    }
}

具有枚举表的数据库

将被转换为枚举的表如下所示:

-- Table name `account_role` will be translated into `AccountRole`
CREATE TABLE enums.account_role (
    "name" varchar(100) NOT NULL,
    description varchar(255) NOT NULL,
    CONSTRAINT account_role_name_key UNIQUE (name)
);

-- Table entries will be translated into enum entries
INSERT INTO enums.account_role ("name",description) VALUES 
('BILLING','Role for contact/address that will be a Billing contact/address'),
('PAYMENT','Role for contact/address that will be a Payment contact/address'),
('SERVICE','Role for contact/address that will be a Service contact/address'),
('SOLD_TO','Role for contact/address that will be a SoldTo contact/address')
;

此数据定义将导致以下自动生成的枚举AccountRole.java:

/*
 * This file is generated by jOOQ.
 */
package com.congerotechnology.ctgcommon.jooq.enums;

public enum AccountRole {
    BILLING("Role for contact/address that will be a Billing contact/address"),
    PAYMENT("Role for contact/address that will be a Payment contact/address"),
    SERVICE("Role for contact/address that will be a Service contact/address"),
    SOLD_TO("Role for contact/address that will be a SoldTo contact/address");

    private final String description;

    private AccountRole(String description) {
        this.description = description;
    }
}

主项目

然后在将要使用此枚举生成器的主项目中,我在pom.xml上设置了以下maven代码:

<dependencies>
...
    <!-- JOOQ custom generator -->
    <dependency>
       <groupId>com.ctg</groupId>
       <artifactId>ctg-jooq-generator</artifactId>
       <version>0.0.1</version>
    </dependency>
...
</dependencies>

<build>
...
    <plugins>
        <!-- JOOQ code generation -->
        <plugin>
            <groupId>org.jooq</groupId>
            <artifactId>jooq-codegen-maven</artifactId>
            <version>${jooq.version}</version>

            <executions>
                <execution>
                    <id>generate-sources</id>
                    <phase>generate-sources</phase>
                    <goals>
                        <goal>generate</goal>
                    </goals>
                </execution>
            </executions>

            <configuration>
                <jdbc>
                    <driver>org.postgresql.Driver</driver>
                    <url>jdbc:postgresql://${env.DB_URL}</url>
                    <user>${env.DB_USER}</user>
                    <password>${env.DB_PASSWORD}</password>
                </jdbc>
                <generator>
                    <name>com.ctg.ctgjooqgenerator.jooq.EnumGenerator</name>

                    <database>
                        <name>org.jooq.meta.postgres.PostgresDatabase</name>
                        <includes>.*</includes>
                        <excludes />
                        <dateAsTimestamp>true</dateAsTimestamp>
                        <inputSchema>enums</inputSchema>
                    </database>
                    <generate>
                        <deprecated>false</deprecated>
                        <instanceFields>true</instanceFields>
                    </generate>
                    <target>
                        <packageName>com.ctg.ctgcommon.jooq.enums</packageName>
                        <directory>target/generated-sources/jooq-postgres</directory>
                    </target>
                </generator>
            </configuration>

            <dependencies>
                <dependency>
                    <groupId>org.postgresql</groupId>
                    <artifactId>postgresql</artifactId>
                    <version>${postgresql.version}</version>
                </dependency>
            </dependencies>
        </plugin>
    </plugins>

答案 2 :(得分:2)

当然,您可以通过几个步骤重新实现已删除的功能:

1。为该枚举实现生成器

您需要覆盖JavaGenerator以实现代码生成,以便将主数据(可能是多个表)转换为枚举。如何运作完全取决于你,例如你可以:

  • 单列主数据表
  • ID / VALUE映射表
  • ID / VALUE /评论映射表
  • 其他布局

2。为这些枚举生成ForcedType个配置

每当引用这样的主数据表时,您应该使用<forcedType/>配置将外键列重新连接到该枚举。 This is best done by configuring your code generation programmatically,因为这样可以让您对jOOQ代码生成配置进行更多动态控制。

This step is documented more in detail in Bill O'Neil's answer

3。防止生成主数据表

除了上述内容之外,您应该从生成的输出中删除主数据表本身。在您的情况下,这应该导致配置:

<excludes>YNM</excludes>

或者,如果您有多个主数据表:

<excludes>YNM|OTHER_MASTER_DATA_TABLE|...</excludes>

排除这些表将阻止从jOOQ客户端代码访问它们,以及删除生成的代码中的外键信息,这可能会造成混淆。