micronaut-projects / micronaut-data

Ahead of Time Data Repositories
Apache License 2.0
465 stars 197 forks source link

Schema Generate doesn't work #3177

Open Soromeister opened 4 days ago

Soromeister commented 4 days ago

Expected Behavior

Schema generation should populate the DB with the expected tables derived from the declared entities.

Actual Behaviour

Nothing gets populated in the DB

Steps To Reproduce

  1. Main Application class:
    
    import io.micronaut.configuration.picocli.PicocliRunner;
    import io.micronaut.context.ApplicationContextBuilder;
    import io.micronaut.context.ApplicationContextConfigurer;
    import io.micronaut.context.annotation.ContextConfigurer;
    import io.micronaut.core.annotation.NonNull;
    import io.micronaut.runtime.Micronaut;
    import lombok.extern.slf4j.Slf4j;
    import picocli.CommandLine.Command;
    import picocli.CommandLine.Option;

@Slf4j @Command(name = "testapp", description = "...", mixinStandardHelpOptions = true) public class Application implements Runnable { @Option(names = {"-v", "--verbose"}, description = "...") boolean verbose;

@Option(names = {"-s", "--server"}, description = "start web server")
boolean server;

@Option(names = {"-c", "--config"}, description = "load config file")
boolean config;

@ContextConfigurer
public static class Configurer implements ApplicationContextConfigurer {
    @Override
    public void configure(@NonNull ApplicationContextBuilder builder) {
        builder.defaultEnvironments("dev");
    }
}

public static void main(String[] args) throws Exception {
    Micronaut.run(Application.class, args);

// PicocliRunner.run(Application.class, args); }

public void run() {
    // business logic here
    if (verbose) {
        log.info("Hi! This is a Micronaut CLI application.");
    }
    if (server) {
        Micronaut.run(Application.class);
    }
    if (config) {
        parseConfigFile("config.properties");
    }
}

private void parseConfigFile(String filePath) {
    log.info("TODO: Implement config file parsing"); //TODO: Implement config file parsing
}

}

2. build.gradle:

//buildscript { // repositories { // mavenCentral() // } // dependencies { // classpath 'org.liquibase:liquibase-core:4.29.2' // } //}

plugins { id 'idea' id 'java' id 'groovy' // id 'org.liquibase.gradle' version '3.0.1' id 'io.freefair.lombok' version '8.10.2' id 'com.github.johnrengelman.shadow' version "8.1.1" id 'io.micronaut.application' version "4.4.2" id 'io.micronaut.test-resources' version "4.4.2" id 'io.micronaut.aot' version "4.4.2" }

version = "0.1" group = "com.example"

idea { module { downloadJavadoc = true downloadSources = true } } repositories { mavenCentral() }

application { mainClass = "com.example.Application" }

java { sourceCompatibility = JavaVersion.VERSION_21 targetCompatibility = JavaVersion.VERSION_21 }

configurations { compileOnly { extendsFrom annotationProcessor } }

dependencies { annotationProcessor 'org.projectlombok:lombok' annotationProcessor 'io.micronaut.data:micronaut-data-processor' annotationProcessor 'io.micronaut:micronaut-http-validation' annotationProcessor 'io.micronaut.eclipsestore:micronaut-eclipsestore-annotations' annotationProcessor 'io.micronaut.serde:micronaut-serde-processor' annotationProcessor 'io.micronaut.spring:micronaut-spring-annotation' annotationProcessor 'io.micronaut.spring:micronaut-spring-boot-annotation' annotationProcessor 'io.micronaut.spring:micronaut-spring-web-annotation' annotationProcessor 'io.micronaut.validation:micronaut-validation-processor' annotationProcessor 'info.picocli:picocli-codegen' annotationProcessor 'org.mapstruct:mapstruct-processor:1.6.2' annotationProcessor 'io.github.linpeilie:mapstruct-plus-processor:1.4.5' annotationProcessor "io.micronaut:micronaut-inject-java" implementation 'info.picocli:picocli' implementation 'io.micronaut.picocli:micronaut-picocli' implementation 'io.micronaut:micronaut-http-server' implementation 'io.micronaut:micronaut-jackson-databind' implementation 'io.micronaut:micronaut-management' implementation 'io.micronaut:micronaut-websocket' implementation 'io.micronaut.data:micronaut-data-hibernate-jpa' implementation 'io.micronaut.data:micronaut-data-spring' implementation 'io.micronaut.data:micronaut-data-spring-jpa' implementation 'io.micronaut.eclipsestore:micronaut-eclipsestore' implementation 'io.micronaut.eclipsestore:micronaut-eclipsestore-annotations' implementation 'io.micronaut.liquibase:micronaut-liquibase' implementation 'io.micronaut.multitenancy:micronaut-multitenancy' implementation 'io.micronaut.problem:micronaut-problem-json' implementation 'io.micronaut.serde:micronaut-serde-jackson' implementation 'io.micronaut.session:micronaut-session' implementation 'io.micronaut.validation:micronaut-validation' implementation 'jakarta.annotation:jakarta.annotation-api' implementation 'jakarta.validation:jakarta.validation-api' implementation 'io.micronaut.sql:micronaut-jdbc-hikari' implementation 'org.springframework:spring-orm' implementation 'org.springframework.boot:spring-boot-starter' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.mapstruct:mapstruct:1.6.2' implementation 'io.github.linpeilie:mapstruct-plus:1.4.5' implementation 'io.github.linpeilie:mapstruct-plus-spring-boot-starter:1.4.5' implementation 'org.projectlombok:lombok-mapstruct-binding:0.2.0' compileOnly 'org.projectlombok:lombok' compileOnly 'io.micronaut:micronaut-http-client' runtimeOnly 'io.micronaut.spring:micronaut-spring-boot' runtimeOnly 'io.micronaut.spring:micronaut-spring-web' // runtimeOnly 'org.liquibase.ext:liquibase-hibernate5:4.27.0' runtimeOnly 'org.postgresql:postgresql' runtimeOnly 'org.slf4j:slf4j-simple' runtimeOnly 'org.yaml:snakeyaml' testAnnotationProcessor 'io.micronaut.spring:micronaut-spring-boot-annotation' testAnnotationProcessor 'io.micronaut.spring:micronaut-spring-web-annotation' testImplementation 'io.micronaut:micronaut-http-client' testImplementation 'net.minidev:json-smart:2.5.1' developmentOnly 'io.micronaut.controlpanel:micronaut-control-panel-management' developmentOnly 'io.micronaut.controlpanel:micronaut-control-panel-ui' // liquibaseRuntime 'javax.xml.bind:jaxb-api:2.3.1' // liquibaseRuntime 'org.liquibase:liquibase-core:4.26.1' // liquibaseRuntime 'org.liquibase:liquibase-groovy-dsl:3.0.2' // liquibaseRuntime 'info.picocli:picocli:4.6.1' // liquibaseRuntime 'org.postgresql:postgresql:42.7.4' // liquibaseRuntime 'org.liquibase.ext:liquibase-hibernate5:3.6' // liquibaseRuntime sourceSets.main.output }

graalvmNative.toolchainDetection = false

micronaut { runtime("netty") testRuntime("spock2") processing { incremental(true) annotations("com.example.*") } aot { // Please review carefully the optimizations enabled below // Check https://micronaut-projects.github.io/micronaut-aot/latest/guide/ for more details optimizeServiceLoading = false convertYamlToJava = false precomputeOperations = true cacheEnvironment = true optimizeClassLoading = true deduceEnvironment = true optimizeNetty = true replaceLogbackXml = false } }

tasks.named("dockerfileNative") { jdkVersion = "21" }

3. application-dev.yml:

endpoints: all: enabled: true sensitive: false health: details-visible: ANONYMOUS loggers: write-sensitive: false

4. application.yml:

micronaut: application: name: testapp server: port: 8080 host: ${HOST_ADDR} session: http: cookie: true header: true datasources: default: driver-class-name: org.postgresql.Driver db-type: postgres dialect: POSTGRES url: jdbc:postgresql://localhost:5432/postgres username: postgres password: '' schema-generate: CREATE_DROP jpa: default: properties: jakarta: persistence: schema-generation: scripts: action: create create-source: metadata create-target: createFile.sql drop-target: dropFile.sql javax: persistence: schema-generation: scripts: action: create create-source: metadata create-target: createFile.sql drop-target: dropFile.sql hibernate: hbm2ddl: auto: create

liquibase:

datasources:

default:

change-log: classpath:db/liquibase-changelog.xml

5. Abstract core entity:

import io.micronaut.data.annotation.DateCreated; import io.micronaut.data.annotation.DateUpdated; import jakarta.persistence.MappedSuperclass; import java.time.LocalDateTime; import org.hibernate.annotations.SoftDelete;

@MappedSuperclass public abstract class CoreEntity {

@DateCreated
private LocalDateTime created_at;

@DateUpdated
private LocalDateTime updated_at;

@SoftDelete
private LocalDateTime deleted_at;

}

7. Example entity:

import com.example.module.common.entity.CoreEntity; import io.micronaut.data.annotation.GeneratedValue; import io.micronaut.data.annotation.GeneratedValue.Type; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.Id; import java.io.Serializable; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import org.hibernate.annotations.ColumnDefault;

@Entity @Getter @Setter @Builder @NoArgsConstructor @AllArgsConstructor public class ExampleEntity extends CoreEntity implements Serializable {

@Id
@GeneratedValue(Type.UUID)
private Long id;

@Column(nullable = false, unique = true)
private String name;

@Column(nullable = false)
@ColumnDefault("false")
private Boolean status;

}

8. Example repository:

import com.example.module.profile_types.dto.ProfileTypesOutput; import io.micronaut.data.annotation.Repository; import io.micronaut.data.repository.CrudRepository; import io.micronaut.data.repository.jpa.JpaSpecificationExecutor;

@Repository public interface ExampleRepository extends CrudRepository<ExampleEntity, Long>, JpaSpecificationExecutor {

ExampleEntity findByName(String name);

}


At this point, there is no need for service or controller, as schema generation should already be done (at least this is the case with Spring Boot).

Application produces the following output:

02:53:37: Executing 'run --args="-s" -s'...

Task :processResources UP-TO-DATE Task :generateTestResourcesEffectiveLombokConfig UP-TO-DATE Task :compileTestResourcesJava NO-SOURCE Task :compileTestResourcesGroovy NO-SOURCE Task :inspectRuntimeClasspath Task :processTestResourcesResources NO-SOURCE Task :testResourcesClasses UP-TO-DATE [test-resources-service] 02:53:38.498 [main] INFO i.m.c.DefaultApplicationContext$RuntimeConfiguredEnvironment - Established active environments: [test] [test-resources-service] 02:53:38.503 [ForkJoinPool.commonPool-worker-5] INFO i.m.t.e.TestResourcesResolverLoader - Loaded 2 test resources resolvers: io.micronaut.testresources.postgres.PostgreSQLTestResourceProvider, io.micronaut.testresources.testcontainers.GenericTestContainerProvider [test-resources-service] 02:53:38.633 [pool-1-thread-1] INFO o.t.d.DockerClientProviderStrategy - Loaded org.testcontainers.dockerclient.UnixSocketClientProviderStrategy from ~/.testcontainers.properties, will try it first [test-resources-service] 02:53:38.728 [pool-1-thread-1] INFO o.t.d.DockerClientProviderStrategy - Found Docker environment with local Unix socket (unix:///var/run/docker.sock) [test-resources-service] 02:53:38.730 [pool-1-thread-1] INFO o.testcontainers.DockerClientFactory - Docker host IP address is localhost [test-resources-service] 02:53:38.741 [pool-1-thread-1] INFO o.testcontainers.DockerClientFactory - Connected to docker: Server Version: 27.3.1 API Version: 1.47 Operating System: OrbStack Total Memory: 7997 MB [test-resources-service] 02:53:38.746 [pool-1-thread-1] INFO o.testcontainers.images.PullPolicy - Image pull policy will be performed by: DefaultPullPolicy() [test-resources-service] 02:53:38.746 [pool-1-thread-1] INFO o.t.utility.ImageNameSubstitutor - Image name substitution will be performed by: DefaultImageNameSubstitutor (composite of 'ConfigurationFileImageNameSubstitutor' and 'PrefixingImageNameSubstitutor') [test-resources-service] 02:53:38.756 [pool-1-thread-1] INFO tc.testcontainers/ryuk:0.7.0 - Creating container for image: testcontainers/ryuk:0.7.0 [test-resources-service] 02:53:38.853 [pool-1-thread-1] INFO tc.testcontainers/ryuk:0.7.0 - Container testcontainers/ryuk:0.7.0 is starting: 28605a694b0006382d03f9aa2b5537e808ea869830ff18440dc9e7e1c2217dbe [test-resources-service] 02:53:39.024 [pool-1-thread-1] INFO tc.testcontainers/ryuk:0.7.0 - Container testcontainers/ryuk:0.7.0 started in PT0.268288S [test-resources-service] 02:53:39.027 [pool-1-thread-1] INFO o.t.utility.RyukResourceReaper - Ryuk started - will monitor and terminate Testcontainers containers on JVM exit [test-resources-service] 02:53:39.027 [pool-1-thread-1] INFO o.testcontainers.DockerClientFactory - Checking the system... [test-resources-service] 02:53:39.028 [pool-1-thread-1] INFO o.testcontainers.DockerClientFactory - ✔︎ Docker server version should be at least 1.6.0 [test-resources-service] 02:53:39.136 [scheduled-executor-thread-1] INFO i.m.t.server.ExpiryManager - Test resources server will automatically be shutdown if it doesn't receive requests for 60 minutes [test-resources-service] 02:53:39.153 [main] INFO i.m.t.server.TestResourcesService - A Micronaut Test Resources server is listening on port 60205, started in 737ms Task :internalStartTestResourcesService Task :generateEffectiveLombokConfig Task :compileJava Task :compileGroovy NO-SOURCE Task :classes

Task :run


| \/ (_) | | | |\/| | |/ | '/ | ' \ / ` | | | | | | | | | | (| | | () | | | | (| | || | | || |||_|_| _/|| ||_,|_,|\| SLF4J(W): Class path contains multiple SLF4J providers. SLF4J(W): Found provider [org.slf4j.simple.SimpleServiceProvider@258e2e41] SLF4J(W): Found provider [ch.qos.logback.classic.spi.LogbackServiceProvider@3d299e3] SLF4J(W): See https://www.slf4j.org/codes.html#multiple_bindings for an explanation. SLF4J(I): Actual provider is of type [org.slf4j.simple.SimpleServiceProvider@258e2e41] [main] INFO io.micronaut.context.DefaultApplicationContext$RuntimeConfiguredEnvironment - Established active environments: [dev] [main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting... [main] INFO com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection org.postgresql.jdbc.PgConnection@7048f722 [main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed. [main] INFO org.hibernate.Version - HHH000412: Hibernate ORM core version 6.5.2.Final [main] INFO org.hibernate.cache.internal.RegionFactoryInitiator - HHH000026: Second-level cache disabled [main] INFO org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator - HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration) [main] INFO io.micronaut.runtime.Micronaut - Startup completed in 1757ms. Server Running: http://127.0.0.1:8080

I have no idea why it's not generating.

Environment Information

M1 Mac macOS 14.7 PostgreSQL 17.0

Example Application

No response

Version

4.6.3

Soromeister commented 4 days ago

Switching to PicocliRunner.run(Application.class, args); and starting server via --server argument will result in this output (still not populating DB with schema):

> Task :run
 __  __ _                                  _   
|  \/  (_) ___ _ __ ___  _ __   __ _ _   _| |_ 
| |\/| | |/ __| '__/ _ \| '_ \ / _` | | | | __|
| |  | | | (__| | | (_) | | | | (_| | |_| | |_ 
|_|  |_|_|\___|_|  \___/|_| |_|\__,_|\__,_|\__|
SLF4J(W): Class path contains multiple SLF4J providers.
SLF4J(W): Found provider [org.slf4j.simple.SimpleServiceProvider@258e2e41]
SLF4J(W): Found provider [ch.qos.logback.classic.spi.LogbackServiceProvider@3d299e3]
SLF4J(W): See https://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J(I): Actual provider is of type [org.slf4j.simple.SimpleServiceProvider@258e2e41]
[main] INFO io.micronaut.context.DefaultApplicationContext$RuntimeConfiguredEnvironment - Established active environments: [cli]
[main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...
[main] INFO com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection org.postgresql.jdbc.PgConnection@7728643a
[main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed.
[main] INFO org.hibernate.Version - HHH000412: Hibernate ORM core version 6.5.2.Final
[main] INFO org.hibernate.cache.internal.RegionFactoryInitiator - HHH000026: Second-level cache disabled
[main] INFO org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator - HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
[main] INFO io.micronaut.context.DefaultApplicationContext$RuntimeConfiguredEnvironment - Established active environments: [dev]
[main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-2 - Starting...
[main] INFO com.zaxxer.hikari.pool.HikariPool - HikariPool-2 - Added connection org.postgresql.jdbc.PgConnection@5c997de8
[main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-2 - Start completed.
[main] INFO org.hibernate.cache.internal.RegionFactoryInitiator - HHH000026: Second-level cache disabled
[main] INFO org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator - HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
[main] INFO io.micronaut.runtime.Micronaut - Startup completed in 301ms. Server Running: http://127.0.0.1:8080
[main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown initiated...
[main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown completed.
radovanradic commented 4 days ago

I see that file createFile.sql gets created with this content

create table example_entity (status boolean default false not null, created_at timestamp(6), deleted_at timestamp(6), id bigint not null, updated_at timestamp(6), name varchar(255) not null unique, primary key (id));

Isn't it what is configured here

  default:
    properties:
      jakarta:
        persistence:
          schema-generation:
            scripts:
              action: create
              create-source: metadata
              create-target: createFile.sql
              drop-target: dropFile.sql

and I think it works as expected.