"timestamp with time zone" postgres 中的 Jooq 绑定

Jooq binding for "timestamp with time zone" type in postgres

and support will not come until v3.8.

使用简单的转换器通常可以工作,但某些类型除外,例如 postgres 的 TIMESTAMP WITH TIME ZONE,它需要自定义绑定。所以我试着写一个,但生成的 XxxRecord 类 仍然使用 Timestamp 数据类型作为我数据库中的 TIMESTAMP WITH TIME ZONE 字段。

我需要在下面的代码中更改什么才能将 postgres 的 TIMESTAMP WITH TIME ZONE 视为 jooq 生成的 类 中的 Instant

转换器

public class TimestampConverter implements Converter<Timestamp, Instant> {
  @Override public Instant from(Timestamp ts) {
    return ts == null ? null : ts.toInstant();
  }
  @Override public Timestamp to(Instant instant) {
    return instant == null ? null : Timestamp.from(instant);
  }
  @Override public Class<Timestamp> fromType() { return Timestamp.class; }
  @Override public Class<Instant> toType() { return Instant.class; }
}

自定义绑定

public class TimestampBinding implements Binding<Timestamp, Instant> {

  private static final Converter<Timestamp, Instant> converter = new TimestampConverter();

  private final DefaultBinding<Timestamp, Instant> delegate = 
                                                       new DefaultBinding<> (converter());

  @Override public Converter<Timestamp, Instant> converter() { return converter; }

  @Override public void sql(BindingSQLContext<Instant> ctx) throws SQLException {
    delegate.sql(ctx);
  }

  //etc. same for all other overriden methods.
}

pom.xml(摘录)

<customType>
  <name>java.time.Instant</name>
  <type>java.time.Instant</type>
  <binding>xxx.TimestampBinding</binding>
</customType>

...

<forcedType>
  <name>java.time.Instant</name>
  <types>timestamp with time zone</types>
</forcedType>

一种方法是用反斜杠转义 <types> 中的空格,如下所示:

<types>timestamp\ with\ time\ zone</types>

您不能只在 <types> 中使用常规空格,因为默认情况下,org.jooq.util.AbstractDatabaseparse regular expressions in COMMENTS mode which makes the created Pattern object ignore whitespace in your regex. You could also do something like <types>timestamp.*zone</types>, or specify your own <regexFlags>.

以下是适用于我的完整 Maven jooq-codegen-maven 插件标签。我还发现 <binding> 是不必要的。

<plugin>
    <groupId>org.jooq</groupId>
    <artifactId>jooq-codegen-maven</artifactId>
    <version>3.7.0</version>

    <executions>
        <execution>
            <goals>
                <goal>generate</goal>
            </goals>
        </execution>
    </executions>

    <configuration>

        <jdbc>
            <driver>org.postgresql.Driver</driver>
            <url>jdbc:postgresql:postgres</url>
            <user>postgres</user>
            <password>mypass</password>
        </jdbc>

        <generator>
            <database>
                <customTypes>
                    <customType>
                        <name>Instant</name>
                        <type>java.time.Instant</type>
                        <converter>xxx.TimestampConverter</converter>
                    </customType>
                </customTypes>

                <forcedTypes>
                    <forcedType>
                        <name>Instant</name>
                        <types>timestamp\ with\ time\ zone</types>
                    </forcedType>
                </forcedTypes>

                <name>org.jooq.util.postgres.PostgresDatabase</name>
                <includes>author</includes>
                <excludes/>
                <inputSchema>public</inputSchema>
            </database>
            <target>
                <packageName>xxx.table</packageName>
                <directory>target/generated-sources/jooq</directory>
            </target>
        </generator>
    </configuration>
</plugin>

Jooq 3.11 似乎在启用 javaTimeTypes 时将 TIMESTAMP WITH TIME ZONE 变成了 OffsetDateTime,并且它还抱怨 customTypes 被弃用,所以我不是能够得到对我有用的其他答案。

以下是我如何使用 gradle jooq 插件让它工作:

// inside the jooq...generator.database of build.gradle:
forcedTypes {
    forcedType {
        userType = 'java.time.Instant'
        converter = '''
        org.jooq.Converter.ofNullable(
            java.time.OffsetDateTime.class,
            java.time.Instant.class,
            o -> o.toInstant(),
            i -> i.atOffset(java.time.ZoneOffset.UTC))
        '''
        types = 'timestamp\ with\ time\ zone'
    }
}

对于 Maven 或手动调用代码生成器,将其转换为 XML 应该很容易,因为 gradle 插件的参数与 XML 的结构完全匹配。请注意 Groovy 语法要求 types 模式中的反斜杠加倍,因此如果转换为 XML.

则需要进行调整

这使用内联转换器将 Jooq 当前使用的 OffsetDateTime 转换为 Instant。无需外部转换器 class。