jOOQ / jOOQ

jOOQ is the best way to write SQL in Java
https://www.jooq.org
Other
6.15k stars 1.21k forks source link

JPADatabase should throw Hibernate's exceptions when there is anything going wrong with the SchemaExport #17274

Closed javiercj93 closed 1 month ago

javiercj93 commented 1 month ago

Your question

I've tried to follow the documentation here, however, I was unable to make it work and I could not find any working example. What I am trying to achieve is simple, I want to generate jooq code based on jpa entities.

In a multimodule project I've created an entitties module which contains a single entity:

@Entity
@Table(name = "entity_a")
public class EntityA {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "name")
    private String name;

    @Column(name = "description")
    private String description;

    @Column(name = "value")
    private Integer value;
}

Then in my application module, I've added the following plugin configuration:

<plugin>
      <groupId>org.jooq</groupId>
      <artifactId>jooq-codegen-maven</artifactId>
      <version>3.19.11</version>
      <dependencies>
        <dependency>
          <groupId>com.javier</groupId>
          <artifactId>entities</artifactId>
          <version>${project.version}</version>
        </dependency>
      </dependencies>
      <executions>
        <execution>
          <goals>
            <goal>generate</goal>
          </goals>
          <configuration>

            <!-- Generator configuration -->
            <generator>
              <!-- Database schema -->
              <database>
                <name>org.jooq.meta.extensions.jpa.JPADatabase</name>
                <includes>.*</includes>
                <properties>
                  <!-- Set packages to scan for JPA entities -->
                  <property>
                    <key>packages</key>
                    <value>com.javier.entities</value>
                  </property>

                  <!-- Explicitly set Hibernate dialect -->
                  <property>
                    <key>hibernate.dialect</key>
                    <value>org.hibernate.dialect.PostgreSQLDialect</value>
                  </property>

                  <!-- Use attribute converters if necessary -->
                  <property>
                    <key>useAttributeConverters</key>
                    <value>true</value>
                  </property>

                  <!-- Unqualified schema handling -->
                  <property>
                    <key>unqualifiedSchema</key>
                    <value>none</value>
                  </property>
                </properties>
              </database>

              <!-- Target package and directory -->
              <target>
                <packageName>com.javier.application.generated</packageName> <!-- Set your desired package name -->
                <directory>src/main/java</directory>
              </target>
              <generate>
                <pojos>true</pojos>
                <daos>true</daos>
              </generate>

              <!-- Define the strategy for generating DTOs and DAOs -->
              <strategy>
                <name>org.jooq.codegen.DefaultGeneratorStrategy</name>
              </strategy>
            </generator>
          </configuration>
        </execution>
      </executions>
    </plugin>

When I run it, I can see the following:

[INFO] Entities added           : Number of entities added: 1

But then nothing is generated, could I get a link to an example or something I could use as a reference? The following examples in a similar issue does not seem available anymore:

https://github.com/etiennestuder/gradle-jooq-plugin/issues/194#issuecomment-959044176

jOOQ Version

3.19.11

Database product and version

mysql8

Java Version

openjdk v17

JDBC / R2DBC driver name and version (include name if unofficial driver)

No response

lukaseder commented 1 month ago

Thanks for your message. Could you please provide the complete INFO log output

javiercj93 commented 1 month ago

Thanks for your reply!

[INFO] No <inputCatalog/> was provided. Generating ALL available catalogs instead.
[INFO] No <inputSchema/> was provided. Generating ALL available schemata instead.
Sep 19, 2024 4:02:00 PM org.hibernate.Version logVersion
INFO: HHH000412: Hibernate ORM core version 5.6.15.Final
[INFO] Entities added           : Number of entities added: 1
Sep 19, 2024 4:02:01 PM org.hibernate.annotations.common.reflection.java.JavaReflectionManager <clinit>
INFO: HCANN000001: Hibernate Commons Annotations {5.1.2.Final}
Sep 19, 2024 4:02:01 PM org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
Sep 19, 2024 4:02:01 PM org.hibernate.tool.hbm2ddl.SchemaExport execute
INFO: HHH000227: Running hbm2ddl schema export
Sep 19, 2024 4:02:01 PM org.hibernate.jpa.internal.util.LogHelper logPersistenceUnitInformation
INFO: HHH000204: Processing PersistenceUnitInfo [name: AttributeConverterExtractor]
Sep 19, 2024 4:02:01 PM org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
Sep 19, 2024 4:02:02 PM org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator initiateService
INFO: HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
[INFO] License parameters       
[INFO] ----------------------------------------------------------
[INFO]   Thank you for using jOOQ and jOOQ's code generator
[INFO]                          
[INFO] Database parameters      
[INFO] ----------------------------------------------------------
[INFO]   dialect                : H2
[INFO]   URL                    : 
[INFO]   target dir             : /Users/javer/jooq-demo/application/src/main/java
[INFO]   target package         : org.jooq.example.jpa.jooq
[INFO]   includes               : [.*]
[INFO]   excludes               : []
[INFO]   includeExcludeColumns  : false
[INFO] ----------------------------------------------------------
[INFO]                          
[INFO] JavaGenerator parameters 
[INFO] ----------------------------------------------------------
[INFO] annotations              
[INFO]   generated              : false
[INFO]   JPA                    : false
[INFO]   JPA version            : 
[INFO]   validation             : false
[INFO]   spring                 : false
[INFO] comments                 
[INFO]   comments               : true
[INFO]   on attributes          : true
[INFO]   on catalogs            : true
[INFO]   on columns             : true
[INFO]   on embeddables         : true
[INFO]   on keys                : true
[INFO]   on links               : true
[INFO]   on packages            : true
[INFO]   on parameters          : true
[INFO]   on queues              : true
[INFO]   on routines            : true
[INFO]   on schemas             : true
[INFO]   on sequences           : true
[INFO]   on tables              : true
[INFO]   on udts                : true
[INFO] sources                  
[INFO]   sources                : true
[INFO]   sources on views       : true
[INFO] global references        
[INFO]   global references      : true
[INFO]   catalogs               : true
[INFO]   domains                : true
[INFO]   indexes                : true
[INFO]   keys                   : true
[INFO]   links                  : true
[INFO]   queues                 : true
[INFO]   routines               : true
[INFO]   schemas                : true
[INFO]   sequences              : true
[INFO]   tables                 : true
[INFO]   udts                   : true
[INFO] object types             
[INFO]   daos                   : false
[INFO]   indexes                : true
[INFO]   instance fields        : true
[INFO]   interfaces             : false
[INFO]   interfaces (immutable) : false
[INFO]   javadoc                : true
[INFO]   keys                   : true
[INFO]   links                  : true
[INFO]   pojos                  : false
[INFO]   pojos (immutable)      : false
[INFO]   queues                 : true
[INFO]   records                : true
[INFO]   routines               : true
[INFO]   sequences              : true
[INFO]   sequenceFlags          : true
[INFO]   table-valued functions : true
[INFO]   tables                 : true
[INFO]   udts                   : true
[INFO]   relations              : true
[INFO] other                    
[INFO]   deprecated code        : true
[INFO] ----------------------------------------------------------
[INFO]                          
[INFO] Generation remarks       
[INFO] ----------------------------------------------------------
[INFO]                          
[INFO] ----------------------------------------------------------
[INFO] Generating catalogs      : Total: 1
[INFO] Version                  : Database version is supported by dialect H2: 2.2.224 (2023-09-17)
[INFO] ARRAYs fetched           : 0 (0 included, 0 excluded)
[INFO] Domains fetched          : 0 (0 included, 0 excluded)
[INFO] Tables fetched           : 0 (0 included, 0 excluded)
[INFO] Embeddables fetched      : 0 (0 included, 0 excluded)
[INFO] Enums fetched            : 0 (0 included, 0 excluded)
[INFO] Packages fetched         : 0 (0 included, 0 excluded)
[INFO] Routines fetched         : 0 (0 included, 0 excluded)
[INFO] Sequences fetched        : 0 (0 included, 0 excluded)
[INFO] UDTs fetched             : 0 (0 included, 0 excluded)
[INFO] Excluding empty catalog  : 
[INFO] Affected files: 0        
[INFO] Modified files: 0        
[INFO] No modified files        : This code generation run has not produced any file modifications.
This means, the schema has not changed, and no other parameters (jOOQ version, driver version, database version,
and any configuration elements) have changed either.

In automated builds, it is recommended to prevent unnecessary code generation runs. This run took: 300.331ms
Possible means to prevent this:
- Use manual code generation and check in generated sources: https://www.jooq.org/doc/latest/manual/code-generation/codegen-version-control/
- Use schema version providers: https://www.jooq.org/doc/latest/manual/code-generation/codegen-advanced/codegen-config-database/codegen-database-version-providers/
- Use gradle tasks and inputs: https://docs.gradle.org/current/userguide/incremental_build.html
lukaseder commented 1 month ago

Ah, I see, you're probably generating stuff into a "public" schema (due to the org.hibernate.dialect.PostgreSQLDialect), but we're using H2 behind the scenes to reverse engineer what Hibernate generates, and that will default to the "PUBLIC" schema instead - could that be it?

I'll try to reproduce it tomorrow, but you could try removing that. It's not really needed.

javiercj93 commented 1 month ago

It did not work either without

<property>
  <key>hibernate.dialect</key>
  <value>org.hibernate.dialect.PostgreSQLDialect</value>
</property>
lukaseder commented 1 month ago

I'm afraid I don't see what could be the problem. I cannot reproduce any such issue with our integration tests. Can you provide a more complete reproducer, e.g. based on our template here? https://github.com/jOOQ/jOOQ-mcve

If that's too much effort, some other troubleshooting ideas:

javiercj93 commented 1 month ago

Thanks for the support @lukaseder, really appreciate it.

I have recreated an example based on the provided templates (I've removed all the other modules and left just an entity module + the "generator" module.

[INFO] Entities added           : Number of entities added: 2
Sep 20, 2024 10:37:46 AM org.hibernate.annotations.common.reflection.java.JavaReflectionManager <clinit>
INFO: HCANN000001: Hibernate Commons Annotations {5.1.2.Final}
Sep 20, 2024 10:37:46 AM org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
Sep 20, 2024 10:37:47 AM org.hibernate.tool.hbm2ddl.SchemaExport execute
INFO: HHH000227: Running hbm2ddl schema export
Sep 20, 2024 10:37:47 AM org.hibernate.jpa.internal.util.LogHelper logPersistenceUnitInformation
INFO: HHH000204: Processing PersistenceUnitInfo [name: AttributeConverterExtractor]
Sep 20, 2024 10:37:47 AM org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
Sep 20, 2024 10:37:47 AM org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator initiateService
INFO: HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
[INFO] License parameters       

This time I added a second entity (EntityB)

Please let me know if you are able to replicate on your side and apologies because it is probably some misconfiguration on my side.

Link to example -> https://github.com/javiercj93/jOOQ-mcve

lukaseder commented 1 month ago

Thanks for the reproducer. I can see how nothing is generated, will investigate.

lukaseder commented 1 month ago

Using a debugger, right after the Hibernate export command, I can see that no tables have been added to the in-memory H2 database. Only the INFORMATION_SCHEMA is present:

image

lukaseder commented 1 month ago

OK, I see. There are some exceptions being swallowed by the schema export:

org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax error in SQL statement "create table entity_a (id bigint generated by default as identity, description varchar(255), name varchar(255), [*]value integer, primary key (id))"; expected "identifier"; SQL statement:
create table entity_a (id bigint generated by default as identity, description varchar(255), name varchar(255), value integer, primary key (id)) [42001-224]

Very unfortunate... You ran into this issue:

A workaround is to quote your identifier: @Column(name = "`value`")

There are two bugs in jOOQ here:

  1. We should throw any exceptions caught by hibernate. There's probably an SPI to extract them from the SchemaExport
  2. We should be able to handle those keywords, which H2 doesn't support as identifiers anymore (it used to, in the past)
lukaseder commented 1 month ago

The H2 keyword specific bug will be this one:

I'll fix this issue here right away, re-throwing Hibernate's errors when exporting the schema

lukaseder commented 1 month ago

Fixed in versions:

Thanks again for your report and your patience, providing the MCVE. I should have tried your actual entity from the issue description when reproducing the problem. I used my own entity and focused only on what could have gone wrong with the configuration...

lukaseder commented 1 month ago

The current fix may lead to this regression:

13:54:34,923 [ERROR] Failed to execute goal org.jooq.trial:jooq-codegen-maven:3.20.0-SNAPSHOT:generate (generate-jpadatabase) on project jooq-test-codegen-java: Error running jOOQ code generation tool: Error while exporting schema: Halting on error : Error executing DDL "drop table if exists master_data.language CASCADE " via JDBC Statement: Schema "MASTER_DATA" not found; SQL statement:

Since we're working on an in-memory database, might as well omit the dropping of the schema

javiercj93 commented 1 month ago

Appreciate your help! Thanks for the explanation and workaround!