All versions: 3.11 | 3.10 | 3.9 | Development versions: 3.12

The code generator allows users to override column data types in three different ways:

All of this can be done using forced types.

Matching of forced types

The <database> configuration's <forcedTypes> element can contain many <forcedType> elements and the generator will always pick the first of these definitions, where all given match predicates match the database column at hand. These are the available match predicates (all are optional) and the generator evaluates them each in turn in the given order:

  1. <objectType>: Must be one of ATTRIBUTE, COLUMN, ELEMENT, PARAMETER, SEQUENCE, or ALL and specifies what type of database objects this forced type is applicable to
  2. <nullability>: Must be one of NULL, NOT_NULL, or ALL and specifies if this forced type is applicable to NULL, NOT NULL, or all definitions
  3. <excludeExpression>: This exclude predicate is a regular expression which is matched against the definition's name; any definition's name matching the regular expression will be considered not matching this forced type
  4. <includeExpression>: This predicate is a regular expression which is matched against the definition's name
  5. <excludeTypes>: This exclude predicate is a regular expression which is matched against the name of the definition's type (provided that it has one); any definition's type name matching the regular expression will be considered not matching this forced type
  6. <includeTypes>: This predicate is a regular expression which is matched against the name of the definition's type (provided that it has one)
  7. <sql>: An SQL query returning all (qualified or unqualified) object names which should be considered to match this forced type; an example is given at the end of this section

Data type rewriting

XML configuration (standalone and Maven)

<configuration xmlns="http://www.jooq.org/xsd/jooq-codegen-3.11.0.xsd">
  <generator>
    <database>
      <!-- The first matching forcedType will be applied to the data type definition. -->
      <forcedTypes>
        <forcedType>

          <!-- Specify any data type that is supported in your database, or if unsupported, a type from org.jooq.impl.SQLDataType -->
          <name>BOOLEAN</name>

          <!-- Add a Java regular expression matching fully-qualified columns. Use the pipe to separate several expressions.
               If provided, both "includeExpression" and "includeTypes" must match. -->
          <includeExpression>.*\.IS_VALID</includeExpression>
          
          <!-- Add a Java regular expression matching data types to be forced to have this type.

               Data types may be reported by your database as:
               - NUMBER              regexp suggestion: NUMBER
               - NUMBER(5)           regexp suggestion: NUMBER\(5\)
               - NUMBER(5, 2)        regexp suggestion: NUMBER\(5,\s*2\)
               - any other form.

               It is thus recommended to use defensive regexes for types.

               If provided, both "includeExpression" and "includeTypes" must match. -->
          <includeTypes>.*</includeTypes>
          
          <!-- Force a type depending on data type nullability. Default is ALL.
          
                - ALL - Force a type regardless of whether data type is nullable or not (default)
                - NULL - Force a type only when data type is nullable
                - NOT_NULL - Force a type only when data type is not null -->
          <nullability>ALL</nullability>
          
          <!-- Force a type on ALL or specific object types, including 
               ATTRIBUTE, COLUMN, ELEMENT, PARAMETER, SEQUENCE -->
          <objectType>ALL</objectType>
        </forcedType>
      </forcedTypes>
    </database>
  </generator>
</configuration>

Programmatic configuration

configuration
  .withGenerator(new Generator(
    .withDatabase(new Database()
      // The first matching forcedType will be applied to the data type definition.
      .withForcedTypes(new ForcedType()
        .withName("BOOLEAN")
        .withIncludeExpression(".*\.IS_VALID")
        .withIncludeTypes(".*")
        .withNullability(Nullability.ALL)
        .withObjectType(ForcedTypeObjectType.ALL)))));

Gradle configuration

myConfigurationName(sourceSets.main) {
  generator {
    database {
      // The first matching forcedType will be applied to the data type definition.
      forcedTypes {
        forcedType {
          name = 'BOOLEAN'
          includeExpression = '.*\.IS_VALID'
          includeTypes = '.*'
          nullability = ALL
          objectType = ALL
        }
      }
    }
  }
}

Mapping to user type with a converter

Both user type mappings work the same way, regardless if you're using a org.jooq.Converter or a org.jooq.Binding.

XML configuration (standalone and Maven)

<configuration xmlns="http://www.jooq.org/xsd/jooq-codegen-3.11.0.xsd">
  <generator>
    <database>
      <!-- The first matching forcedType will be applied to the data type definition. -->
      <forcedTypes>
        <forcedType>

          <!-- Specify the Java type of your custom type. This corresponds to the Converter's <U> type. -->
          <userType>java.time.Instant</userType>

          <!-- Associate that custom type with your converter. -->
          <converter>com.example.LongToInstantConverter</converter>

          <!-- These are the same as for type rewriting -->
          <includeExpression>.*\.DATE_OF_.*</includeExpression>
          <includeTypes>.*</includeTypes>
        </forcedType>
      </forcedTypes>
    </database>
  </generator>
</configuration>

Programmatic configuration

configuration
  .withGenerator(new Generator(
    .withDatabase(new Database()
      // The first matching forcedType will be applied to the data type definition.
      .withForcedTypes(new ForcedType()
        .withUserType("java.time.Instant")
        .withConverter("com.example.LongToInstantConverter")
        .withIncludeExpression(".*\.DATE_OF_.*")
        .withIncludeTypes(".*")))));

Gradle configuration

myConfigurationName(sourceSets.main) {
  generator {
    database {
      // The first matching forcedType will be applied to the data type definition.
      forcedTypes {
        forcedType {
          userType = 'java.time.Instant'
          converter = 'com.example.LongToInstantConverter'
          includeExpression = '.*\.DATE_OF_.*'
          includeTypes = '.*'
        }
      }
    }
  }
}

For more information about using converters, please refer to the manual's section about custom data type conversion.

Mapping to user type with an inline converter

For convenience, you can inline your converter code directly into the configuration instead of providing a class reference.

XML configuration (standalone and Maven)

<configuration xmlns="http://www.jooq.org/xsd/jooq-codegen-3.11.0.xsd">
  <generator>
    <database>
      <!-- The first matching forcedType will be applied to the data type definition. -->
      <forcedTypes>
        <forcedType>

          <!-- Specify the Java type of your custom type. This corresponds to the Converter's <U> type. -->
          <userType>com.example.MyEnum</userType>

          <!-- Associate that custom type with your inline converter. -->
          <converter>org.jooq.Converter.ofNullable(Integer.class, MyEnum.class, i -> MyEnum.values()[i], MyEnum::ordinal)</converter>

          <!-- These are the same as for type rewriting -->
          <includeExpression>.*\.DATE_OF_.*</includeExpression>
          <includeTypes>.*</includeTypes>
        </forcedType>
      </forcedTypes>
    </database>
  </generator>
</configuration>

Programmatic configuration

configuration
  .withGenerator(new Generator(
    .withDatabase(new Database()
      // The first matching forcedType will be applied to the data type definition.
      .withForcedTypes(new ForcedType()
        .withUserType("com.example.MyEnum")
        .withConverter("org.jooq.Converter.ofNullable(Integer.class, MyEnum.class, i -> MyEnum.values()[i], MyEnum::ordinal)")
        .withIncludeExpression(".*\.DATE_OF_.*")
        .withIncludeTypes(".*")))));

Gradle configuration

myConfigurationName(sourceSets.main) {
  generator {
    database {
      // The first matching forcedType will be applied to the data type definition.
      forcedTypes {
        forcedType {
          userType = 'com.example.MyEnum'
          converter = 'org.jooq.Converter.ofNullable(Integer.class, MyEnum.class, i -> MyEnum.values()[i], MyEnum::ordinal)'
          includeExpression = '.*\.DATE_OF_.*'
          includeTypes = '.*'
        }
      }
    }
  }
}

Mapping to an enum user type with a converter

If your user type is a Java enum, you can use the <enumConverter/> convenience flag instead of an explicit converter per enum type. This will apply the built-in org.jooq.impl.EnumConverter.

XML configuration (standalone and Maven)

<configuration xmlns="http://www.jooq.org/xsd/jooq-codegen-3.11.0.xsd">
  <generator>
    <database>
      <!-- The first matching forcedType will be applied to the data type definition. -->
      <forcedTypes>
        <forcedType>

          <!-- Specify the Java type of your custom type. This corresponds to the Converter's <U> type. -->
          <userType>com.example.MyEnum</userType>

          <!-- Apply the built in org.jooq.impl.EnumConverter. -->
          <enumConverter>true</enumConverter>

          <!-- These are the same as for type rewriting -->
          <includeExpression>.*\.MY_STATUS</includeExpression>
          <includeTypes>.*</includeTypes>
        </forcedType>
      </forcedTypes>
    </database>
  </generator>
</configuration>

Programmatic configuration

configuration
  .withGenerator(new Generator(
    .withDatabase(new Database()
      // The first matching forcedType will be applied to the data type definition.
      .withForcedTypes(new ForcedType()
        .withUserType("com.example.MyEnum")
        .withEnumConverter(true)
        .withIncludeExpression(".*\.MY_STATUS")
        .withIncludeTypes(".*")))));

Gradle configuration

myConfigurationName(sourceSets.main) {
  generator {
    database {
      // The first matching forcedType will be applied to the data type definition.
      forcedTypes {
        forcedType {
          userType = 'com.example.MyEnum'
          enumConverter = true
          includeExpression = '.*\.MY_STATUS'
          includeTypes = '.*'
        }
      }
    }
  }
}

Mapping to user type with a binding

Just switch the converter configuration to a binding configuration.

XML configuration (standalone and Maven)

<configuration xmlns="http://www.jooq.org/xsd/jooq-codegen-3.11.0.xsd">
  <generator>
    <database>
      <!-- The first matching forcedType will be applied to the data type definition. -->
      <forcedTypes>
        <forcedType>

          <!-- Specify the Java type of your custom type. This corresponds to the Binding's <U> type. -->
          <userType>java.time.Instant</userType>

          <!-- Associate that custom type with your converter. -->
          <binding>com.example.LongToInstantBinding</binding>

          <!-- These are the same as for type rewriting -->
          <includeExpression>.*\.DATE_OF_.*</includeExpression>
          <includeTypes>.*</includeTypes>
        </forcedType>
      </forcedTypes>
    </database>
  </generator>
</configuration>

Programmatic configuration

configuration
  .withGenerator(new Generator(
    .withDatabase(new Database()
      // The first matching forcedType will be applied to the data type definition.
      .withForcedTypes(new ForcedType()
        .withUserType("java.time.Instant")
        .withBinding("com.example.LongToInstantBinding")
        .withIncludeExpression(".*\.DATE_OF_.*")
        .withIncludeTypes(".*")))));

Gradle configuration

myConfigurationName(sourceSets.main) {
  generator {
    database {
      // The first matching forcedType will be applied to the data type definition.
      forcedTypes {
        forcedType {
          userType = 'java.time.Instant'
          binding = 'com.example.LongToInstantBinding'
          includeExpression = '.*\.DATE_OF_.*'
          includeTypes = '.*'
        }
      }
    }
  }
}

Using SQL to match column names

If you want to match your column names based on more complex criteria not supported by jOOQ yet, you can supply the matching column names using a SQL query that runs against your dictionary views.

XML configuration (standalone and Maven)

<configuration xmlns="http://www.jooq.org/xsd/jooq-codegen-3.11.0.xsd">
  <generator>
    <database>
      <forcedTypes>
        <forcedType>

          <!-- Rewrite types to boolean -->
          <userType>java.lang.Boolean</userType>
          <converter>com.example.YNBooleanConverter</converter>

          <!-- All Oracle columns that have a default of 'Y' or 'N' are probably boolean -->
          <sql>
            SELECT owner || '.' || table_name || '.' || column_name
            FROM all_tab_cols
            WHERE data_default IN ('Y', 'N')
          </sql>
        </forcedType>
      </forcedTypes>
    </database>
  </generator>
</configuration>

Programmatic configuration

configuration
  .withGenerator(new Generator(
    .withDatabase(new Database()
      .withForcedTypes(new ForcedType()
        .withUserType("java.lang.Boolean")
        .withConverter("com.example.YNBooleanConverter")
        .withSql(
           "SELECT owner || '.' || table_name || '.' || column_name "
         + "FROM all_tab_cols "
         + "WHERE data_default IN ('Y', 'N')")))));

Gradle configuration

myConfigurationName(sourceSets.main) {
  generator {
    database {
      // The first matching forcedType will be applied to the data type definition.
      forcedTypes {
        forcedType {
          userType = 'java.lang.Boolean'
          converter = 'com.example.YNBooleanConverter'
          sql = "SELECT owner || '.' || table_name || '.' || column_name FROM all_tab_cols WHERE data_default IN ('Y', 'N')"
        }
      }
    }
  }
}

For more information about using converters, please refer to the manual's section about custom data type bindings.

The jOOQ Logo