JOOQ Code Generation via JPADatabase problem with custom composite user type

980 views Asked by At

I am trying to use JOOQ code generation from JPA Entity. I have already created a dedicated maven module where the code will be generated which has dependency on a module containing all entities as well code generation plugin with of jooq.

To add more clarify on project structure, here are the modules:(The names are made up but the structure reflects the current project i am working on)

net-example
  |- net-example-data (contains both entities and spring data repositories)
  |- net-example-jooq (where jooq plugin below is configured and should generate the code )
  |- net-example-business (business layer)
  |- net-example-api (api layer)

So in the end i want is, when i build net-example-jooq it should be able to produce the jooq classes from entities found in net-example-data.

pom.xml of net-example-jooq

<build>
        .....
        <plugins>
            <plugin>
                <groupId>org.jooq</groupId>
                <artifactId>jooq-codegen-maven</artifactId>
                <version>${jooq.version}</version>
                <!-- The plugin should hook into the generate goal -->
                <executions>
                    <execution>
                        <goals>
                            <goal>generate</goal>
                        </goals>

                    </execution>
                </executions>
                <!-- Specify the plugin configuration.
                     The configuration format is the same as for the standalone code generator -->
                <configuration>
                    <!-- Generator parameters -->
                    <generator>
                        <database>
                            <name>org.jooq.meta.extensions.jpa.JPADatabase</name>
                            <properties>
                                <property>
                                    <key>packages</key>
                                    <value>net.example</value>
                                </property>
                                <property>
                                    <key>useAttributeConverters</key>
                                    <value>true</value>
                                </property>
                                <property>
                                    <key>unqualifiedSchema</key>
                                    <value>none</value>
                                </property>
                                <property>
                                    <key>hibernate.physical_naming_strategy</key>
                                    <value>org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy</value>
                                </property>
                            </properties>
                            <customTypes>
                                <customType>
                                    <name>money-type</name>
                                    <type>org.javamoney.moneta.Money</type>
                                </customType>
                                <customType>
                                    <name>currency-unit-type</name>
                                    <type>javax.money.CurrencyUnit</type>
                                </customType>
                                <customType>
                                    <name>zone-id-type</name>
                                </customType>
                            </customTypes>
                        </database>
                        <target>
                            <packageName>net.example.generated</packageName>
                            <directory>src/main/java</directory>
                        </target>
                    </generator>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>com.h2database</groupId>
                        <artifactId>h2</artifactId>
                        <version>1.4.193</version>
                    </dependency>
                    <dependency>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-data-jpa</artifactId>
                        <version>2.3.5.RELEASE</version>
                    </dependency>
                    <dependency>
                        <groupId>net.example</groupId>
                        <artifactId>example-data</artifactId>
                        <version>${project.version}</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
...

And here is one of entities containing the custom type.

@Entity
public class Example {

   @Id
   private UUID id;
   
   @Column(name = "NAME")
   private String name;


   @Columns(columns = {
            @Column(name = "CURRENCY"),
            @Column(name = "AMOUNT")
    })
    private Money moneyAmount; // org.javamoney.moneta.Money 

   ....

}

Custom types are defined with the package.info

@TypeDef(name = "money-type", typeClass = PersistentMoneyAmountAndCurrency.class, defaultForType = Money.class)
@TypeDef(name = "currency-unit-type", typeClass = PersistentCurrencyUnit.class, defaultForType = CurrencyUnit.class)
@TypeDef(name = "zone-id-type", typeClass = PersistentZoneIdAsString.class, defaultForType = ZoneId.class)
package net.example.data;

When i run mvn compile the project from the root directory (includes data module, jooq module and the other) i get the following error on the build of jooq module.

...
[ERROR] Failed to execute goal org.jooq:jooq-codegen-maven:3.14.8:generate (default) on project enmacc-server-jooq: Error running jOOQ code generation tool: Error while exporting schema: Could not determine type for column moneyAmount of type org.hibernate.type.SerializableType: java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 1 -> [Help 1]
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.jooq:jooq-codegen-maven:3.14.8:generate (default) on project enmacc-server-jooq: Error running jOOQ code generation tool
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:215)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:156)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:148)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:81)
    at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:56)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:128)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:305)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:192)
    at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:105)
    at org.apache.maven.cli.MavenCli.execute (MavenCli.java:957)
    at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:289)
    at org.apache.maven.cli.MavenCli.main (MavenCli.java:193)
    at sun.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke (Method.java:498)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:282)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:225)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:406)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:347)
Caused by: org.apache.maven.plugin.MojoExecutionException: Error running jOOQ code generation tool
    at org.jooq.codegen.maven.Plugin.execute (Plugin.java:210)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo (DefaultBuildPluginManager.java:137)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:210)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:156)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:148)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:81)
    at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:56)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:128)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:305)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:192)
    at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:105)
    at org.apache.maven.cli.MavenCli.execute (MavenCli.java:957)
    at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:289)
    at org.apache.maven.cli.MavenCli.main (MavenCli.java:193)
    at sun.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke (Method.java:498)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:282)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:225)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:406)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:347)
Caused by: org.jooq.exception.DataAccessException: Error while exporting schema
    at org.jooq.meta.extensions.AbstractInterpretingDatabase.connection (AbstractInterpretingDatabase.java:103)
    at org.jooq.meta.extensions.AbstractInterpretingDatabase.create0 (AbstractInterpretingDatabase.java:77)
    at org.jooq.meta.AbstractDatabase.create (AbstractDatabase.java:296)
    at org.jooq.meta.AbstractDatabase.create (AbstractDatabase.java:285)
    at org.jooq.meta.AbstractDatabase.setConnection (AbstractDatabase.java:275)
    at org.jooq.codegen.GenerationTool.run0 (GenerationTool.java:532)
    at org.jooq.codegen.GenerationTool.run (GenerationTool.java:233)
    at org.jooq.codegen.GenerationTool.generate (GenerationTool.java:228)
    at org.jooq.codegen.maven.Plugin.execute (Plugin.java:207)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo (DefaultBuildPluginManager.java:137)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:210)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:156)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:148)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:81)
    at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:56)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:128)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:305)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:192)
    at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:105)
    at org.apache.maven.cli.MavenCli.execute (MavenCli.java:957)
    at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:289)
    at org.apache.maven.cli.MavenCli.main (MavenCli.java:193)
    at sun.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke (Method.java:498)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:282)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:225)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:406)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:347)
Caused by: org.hibernate.MappingException: Could not determine type for column minimum_price_fluctuation_amount of type org.hibernate.type.SerializableType: java.lang.ArrayIndexOutOfBoundsException
    at org.hibernate.mapping.Column.getSqlTypeCode (Column.java:213)
    at org.hibernate.mapping.Column.getSqlType (Column.java:238)
    at org.hibernate.tool.schema.internal.StandardTableExporter.getSqlCreateStrings (StandardTableExporter.java:96)
    at org.hibernate.tool.schema.internal.StandardTableExporter.getSqlCreateStrings (StandardTableExporter.java:30)
    at org.hibernate.tool.schema.internal.SchemaCreatorImpl.createFromMetadata (SchemaCreatorImpl.java:315)
    at org.hibernate.tool.schema.internal.SchemaCreatorImpl.performCreation (SchemaCreatorImpl.java:166)
    at org.hibernate.tool.schema.internal.SchemaCreatorImpl.doCreation (SchemaCreatorImpl.java:135)
    at org.hibernate.tool.schema.internal.SchemaCreatorImpl.doCreation (SchemaCreatorImpl.java:121)
    at org.hibernate.tool.hbm2ddl.SchemaExport.doExecution (SchemaExport.java:296)
    at org.hibernate.tool.hbm2ddl.SchemaExport.execute (SchemaExport.java:249)
    at org.hibernate.tool.hbm2ddl.SchemaExport.execute (SchemaExport.java:228)
    at org.hibernate.tool.hbm2ddl.SchemaExport.create (SchemaExport.java:220)
    at org.jooq.meta.extensions.jpa.JPADatabase.export (JPADatabase.java:156)
    at org.jooq.meta.extensions.AbstractInterpretingDatabase.connection (AbstractInterpretingDatabase.java:100)
    at org.jooq.meta.extensions.AbstractInterpretingDatabase.create0 (AbstractInterpretingDatabase.java:77)
    at org.jooq.meta.AbstractDatabase.create (AbstractDatabase.java:296)
    at org.jooq.meta.AbstractDatabase.create (AbstractDatabase.java:285)
    at org.jooq.meta.AbstractDatabase.setConnection (AbstractDatabase.java:275)
    at org.jooq.codegen.GenerationTool.run0 (GenerationTool.java:532)
    at org.jooq.codegen.GenerationTool.run (GenerationTool.java:233)
    at org.jooq.codegen.GenerationTool.generate (GenerationTool.java:228)
    at org.jooq.codegen.maven.Plugin.execute (Plugin.java:207)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo (DefaultBuildPluginManager.java:137)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:210)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:156)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:148)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:81)
    at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:56)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:128)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:305)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:192)
    at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:105)
    at org.apache.maven.cli.MavenCli.execute (MavenCli.java:957)
    at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:289)
    at org.apache.maven.cli.MavenCli.main (MavenCli.java:193)
    at sun.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke (Method.java:498)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:282)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:225)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:406)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:347)
Caused by: java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 1
    at org.hibernate.mapping.Column.getSqlTypeCode (Column.java:200)
    at org.hibernate.mapping.Column.getSqlType (Column.java:238)
    at org.hibernate.tool.schema.internal.StandardTableExporter.getSqlCreateStrings (StandardTableExporter.java:96)
    at org.hibernate.tool.schema.internal.StandardTableExporter.getSqlCreateStrings (StandardTableExporter.java:30)
    at org.hibernate.tool.schema.internal.SchemaCreatorImpl.createFromMetadata (SchemaCreatorImpl.java:315)
    at org.hibernate.tool.schema.internal.SchemaCreatorImpl.performCreation (SchemaCreatorImpl.java:166)
    at org.hibernate.tool.schema.internal.SchemaCreatorImpl.doCreation (SchemaCreatorImpl.java:135)
    at org.hibernate.tool.schema.internal.SchemaCreatorImpl.doCreation (SchemaCreatorImpl.java:121)
    at org.hibernate.tool.hbm2ddl.SchemaExport.doExecution (SchemaExport.java:296)
    at org.hibernate.tool.hbm2ddl.SchemaExport.execute (SchemaExport.java:249)
    at org.hibernate.tool.hbm2ddl.SchemaExport.execute (SchemaExport.java:228)
    at org.hibernate.tool.hbm2ddl.SchemaExport.create (SchemaExport.java:220)
    at org.jooq.meta.extensions.jpa.JPADatabase.export (JPADatabase.java:156)
    at org.jooq.meta.extensions.AbstractInterpretingDatabase.connection (AbstractInterpretingDatabase.java:100)
    at org.jooq.meta.extensions.AbstractInterpretingDatabase.create0 (AbstractInterpretingDatabase.java:77)
    at org.jooq.meta.AbstractDatabase.create (AbstractDatabase.java:296)
    at org.jooq.meta.AbstractDatabase.create (AbstractDatabase.java:285)
    at org.jooq.meta.AbstractDatabase.setConnection (AbstractDatabase.java:275)
    at org.jooq.codegen.GenerationTool.run0 (GenerationTool.java:532)
    at org.jooq.codegen.GenerationTool.run (GenerationTool.java:233)
    at org.jooq.codegen.GenerationTool.generate (GenerationTool.java:228)
    at org.jooq.codegen.maven.Plugin.execute (Plugin.java:207)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo (DefaultBuildPluginManager.java:137)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:210)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:156)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:148)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117)


For a simple custom type if i use JPA attribute converters then it would work fine. I am aware that there is no direct support for matching multiple column to a single attribute via JPA Attribute converters (if i am not wrong)

Could anyone direct me here how to handle composite types for JOOQ code generation with JPADatabase? Thanks.

UPDATE:

The problem regarding the code generation was about the projection structure and where the classes were missing on the classpath. However regarding handling of composite types please refer to the accepted answer.

1

There are 1 answers

2
Lukas Eder On BEST ANSWER

Regarding the error

I'm assuming you have missing dependencies on your code generation class path. Once you update your question, I'll update my answer.

Regarding jOOQ code generation support for @TypeDef etc.

jOOQ won't support your generated composite types in generated code out of the box, you'll still have to add forced type configurations for that, possibly embeddable type configurations:

Note that the JPADatabase offers a quick win by integrating with simple JPA defined schemas very quickly. It has its caveats. For best results, I recommend going DDL first (and generate both jOOQ code and JPA model from that), because it will be much easier to put your schema change management under version control, e.g. via Flyway or Liquibase.