Generate DDL with spring boot using a custom delimiter

René Link

I want generate create and drop ddl scripts using spring boot v1.4.3 with JPA - Hibernate 5.0.11.

Most answers I found use the javax.persistence.schema-generation properties. E.g. https://stackoverflow.com/a/36966419/974186

The problem with this approach is the it outputs the sql statements without an delimiter. E.g.

create table ... (...)
create table ... (...)

I want it to output the statements with the delimiter ;

create table ... (...);
create table ... (...);

But I can't find any javax.persistence.schema-generation property to configure it.

So I thought to use the SchemaExport from hibernate, because you can set the delimiter property. But to create a SchemaExport I need a MetadataImplementor (non deprected api).

I can not figure out how to get a MetadataImplementor from spring boot.

Does anyone know if there is either

  • a javax.persistence.schema-generation property to define the delimiter
  • or how to create a SchemaExport (get the dependencies)
  • or has another solution?

Here is some code you can play with

@SpringBootApplication
@ComponentScan(basePackageClasses = Application.class)
@EntityScan(basePackageClasses = User.class)
public class Application {

    @Bean
    public ApplicationRunner getApplicationRunner() {
        return new ApplicationRunner() {

            public void run(ApplicationArguments args) throws Exception {
                // MetadataImplementor metadataImplementor = ???;
                // new SchemaExport(metadataImplementor);
            }
        };
    }

    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(Application.class);
        application.run(args);
    }

}

Entity Class

@Entity
public class User {

    @Id
    @GeneratedValue
    private Long id;
    
    private String name;
    
    public Long getId() {
        return id;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
}

Another entity class

@Entity
public class Person {

    @Id
    @GeneratedValue
    private Long id;
    
    private String name;
    
    public Long getId() {
        return id;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
}

application.properties

spring.jpa.properties.javax.persistence.schema-generation.create-source=metadata
spring.jpa.properties.javax.persistence.schema-generation.scripts.action=create
spring.jpa.properties.javax.persistence.schema-generation.scripts.create-target=create.sql

maven dependencies

<properties>
    <spring.boot.version>1.4.3.RELEASE</spring.boot.version>
</properties>

<dependencyManagement>
    <dependencies>
        <dependency>
            <!-- Import dependency management from Spring Boot -->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>${spring.boot.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
    </dependency>
</dependencies>   

With Hibernate 5.0

I just tried the code above with hibernate 5.0.11.Final. The only thing you must change is

SchemaExport schemaExport = new SchemaExport((MetadataImplementor) metadata);
schemaExport.setDelimiter(";");
schemaExport.setFormat(false);
schemaExport.setOutputFile(dropAndCreateDdlFile.getAbsolutePath());

schemaExport.execute(true, false, false, false);

or of course let the java configuration return a MetadataImplementor instead of Metadata and change the ApplicationRunner constructor param.

René Link

Finally after a lot of investigation I think I found an easy solution that uses public APIs. The solution I found uses hibernate 5.2 (more concrete 5.2.6.Final). But I think it can also be adapted to 5.0

Here is my spring java configuration

@Configuration
@AutoConfigureAfter({ HibernateJpaAutoConfiguration.class })
public class HibernateJavaConfig {

    @ConditionalOnMissingBean({ Metadata.class })
    @Bean
    public Metadata getMetadata(StandardServiceRegistry standardServiceRegistry,
            PersistenceUnitInfo persistenceUnitInfo) {
        MetadataSources metadataSources = new MetadataSources(standardServiceRegistry);

        List<String> managedClassNames = persistenceUnitInfo.getManagedClassNames();
        for (String managedClassName : managedClassNames) {
            metadataSources.addAnnotatedClassName(managedClassName);
        }

        Metadata metadata = metadataSources.buildMetadata();
        return metadata;
    }

    @ConditionalOnMissingBean({ StandardServiceRegistry.class })
    @Bean
    public StandardServiceRegistry getStandardServiceRegistry(JpaProperties jpaProperties) {
        StandardServiceRegistryBuilder ssrb = new StandardServiceRegistryBuilder();

        Map<String, String> properties = jpaProperties.getProperties();
        ssrb.applySettings(properties);

        StandardServiceRegistry ssr = ssrb.build();
        return ssr;
    }

    @ConditionalOnMissingBean({ PersistenceUnitInfo.class })
    @Bean
    public PersistenceUnitInfo getPersistenceUnitInfo(EntityScanPackages entityScanPackages) {
        List<String> packagesToScan = entityScanPackages.getPackageNames();

        DefaultPersistenceUnitManager persistenceUnitManager = new DefaultPersistenceUnitManager();

        String[] packagesToScanArr = (String[]) packagesToScan.toArray(new String[packagesToScan.size()]);
        persistenceUnitManager.setPackagesToScan(packagesToScanArr);
        persistenceUnitManager.afterPropertiesSet();

        PersistenceUnitInfo persistenceUnitInfo = persistenceUnitManager.obtainDefaultPersistenceUnitInfo();
        return persistenceUnitInfo;
    }

}

The java configuration creates a Metadata bean. This bean can be used in hibernate 5.2 to execute a schema generation. E.g.

@Component
public class GenerateDDLApplicationRunner implements ApplicationRunner {

    private Metadata metadata;

    public GenerateDDLApplicationRunner(Metadata metadata) {
        this.metadata = metadata;
    }

    public void run(ApplicationArguments args) throws Exception {
        File dropAndCreateDdlFile = new File("drop-and-create.ddl");
        deleteFileIfExists(dropAndCreateDdlFile);

        SchemaExport schemaExport = new SchemaExport();
        schemaExport.setDelimiter(";");
        schemaExport.setFormat(false);
        schemaExport.setOutputFile(dropAndCreateDdlFile.getAbsolutePath());

        schemaExport.execute(EnumSet.of(TargetType.SCRIPT), Action.BOTH, metadata);
    }

    private void deleteFileIfExists(File dropAndCreateDdlFile) {
        if (dropAndCreateDdlFile.exists()) {
            if (!dropAndCreateDdlFile.isFile()) {
                String msg = MessageFormat.format("File is not a normal file {0}", dropAndCreateDdlFile);
                throw new IllegalStateException(msg);
            }

            if (!dropAndCreateDdlFile.delete()) {
                String msg = MessageFormat.format("Unable to delete file {0}", dropAndCreateDdlFile);
                throw new IllegalStateException(msg);
            }
        }
    }

}

The hibernate dialect is configured using the spring boot application.properties. In my case:

spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL57InnoDBDialect

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

Spring Boot with custom UserDetailsService

Spring boot ddl auto generator

Using a custom DiskSpaceHealthIndicator (Spring Boot Actuator)?

How to create a custom @Query on Spring Boot using a non Entity table?

Custom application properties in spring boot using IntelliJ

Generate DDL using jooq by using schema and table name

spring boot sql database DML and DDL scripts

How to run a custom ddl script on startup of Spring Boot 2

Custom partition of kafka topics using Spring Boot

How to generate a ddl creation script with a modern Spring Boot + Data JPA and Hibernate setup?

How to see the schema sql (DDL) in spring boot?

QueryDsl doesn't generate Q class using Spring Boot and Maven

Spring boot: Handle Custom Exceptions using ControllerAdvice for REST

How to configure a custom RelProvider for Spring HATEOAS when using Spring Boot?

Spring Boot custom HttpMessageConverter

How to Generate an auto UUID using Hibernate on spring boot

Using custom Tag files in JSP with Spring Boot

Generate Verification Mail through firebase using angular/spring-boot

Not able to generate Excel file correctly using Spring Boot and Apache POI

Custom properties in Spring Boot project using Gradle

Spark Custom Receiver to access Cassandra wired using Spring Boot

how to run CUSTOM DDL DML ... On Spring Boot at run time, Without Forcing Hibernate

How to generate a liquibase rollback script using spring boot?

Custom mobile validator using spring boot

Spring boot exception error executing ddl

Inject List of Custom Object to map using spring boot configuration properties

Using ByteBuddy to generate Spring Boot configuration

Running Spring Boot Tests using @DataJpaTest and @Testcontainers results into ddl exceptions

Spring boot Custom Validator