PersistenceException: No persistence provider found for schema generation for persistence-unit named default
Asked Answered
J

6

6

I have tried to set up a gradle task that runs a java main class that is intended to generate a SQL schema.

I have no persistence.xml configuration file.

Here is my configuration and code:

My gradle task:

task JpaSchemaExport(type: JavaExec){
       description "Exports Jpa schema"
       dependsOn compileJava
       main = "com.bignibou.tools.jpa.JpaSchemaExport"
       classpath = sourceSets.main.runtimeClasspath + configurations.compile
    }

My export utility:

public class JpaSchemaExport {

    public static void main(String[] args) throws IOException {
        // execute(args[0], args[1]);
        execute("default", "build/schema.sql");
        System.exit(0);
    }

    public static void execute(String persistenceUnitName, String destination) {
        final Properties persistenceProperties = new Properties();

        // XXX force persistence properties : remove database target
        persistenceProperties.setProperty(org.hibernate.cfg.AvailableSettings.HBM2DDL_AUTO, "");
        persistenceProperties.setProperty(AvailableSettings.SCHEMA_GEN_DATABASE_ACTION, "none");

        // XXX force persistence properties : define create script target from metadata to destination
        // persistenceProperties.setProperty(AvailableSettings.SCHEMA_GEN_CREATE_SCHEMAS, "true");
        persistenceProperties.setProperty(AvailableSettings.SCHEMA_GEN_SCRIPTS_ACTION, "create");
        persistenceProperties.setProperty(AvailableSettings.SCHEMA_GEN_CREATE_SOURCE, "metadata");
        persistenceProperties.setProperty(AvailableSettings.SCHEMA_GEN_SCRIPTS_CREATE_TARGET, destination);

        Persistence.generateSchema(persistenceUnitName, persistenceProperties);
    }
}

My data configuration:

@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
    LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
    emf.setPackagesToScan("com.bignibou.domain");
    emf.setDataSource(dataSource);
    emf.setPersistenceProvider(new HibernatePersistenceProvider());
    emf.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
    emf.setJpaPropertyMap(propertiesMap());
    return emf;
}

private Map<String, String> propertiesMap() {
    Map<String, String> propertiesMap = new HashMap<>();
    propertiesMap.put("hibernate.dialect", hibernateDialect);
    propertiesMap.put("hibernate.hbm2ddl.auto", hibernateHbm2ddlAuto);
    propertiesMap.put("hibernate.ejb.naming_strategy", hibernateEjbNamingStrategy);
    propertiesMap.put("hibernate.connection.charSet", hibernateConnectionCharset);
    propertiesMap.put("hibernate.show_sql", hibernateLogSqlInfo);
    propertiesMap.put("hibernate.format_sql", hibernateLogSqlInfo);
    propertiesMap.put("hibernate.use_sql_comments", hibernateLogSqlInfo);
    propertiesMap.put("hibernate.generate_statistics", hibernateGenerateStatistics);
    propertiesMap.put("hibernate.cache.use_second_level_cache", hibernateCacheUseSecondLevelCache);
    propertiesMap.put("hibernate.cache.region.factory_class", "org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory");
    propertiesMap.put("javax.persistence.sharedCache.mode", "ENABLE_SELECTIVE");
    return propertiesMap;
}

Here is the exception I get:

Exception in thread "main" javax.persistence.PersistenceException: No persistence provider found for schema generation for persistence-unit named default
 at javax.persistence.Persistence.generateSchema(Persistence.java:93)
 at com.bignibou.tools.jpa.JpaSchemaExport.execute(JpaSchemaExport.java:31)
 at com.bignibou.tools.jpa.JpaSchemaExport.main(JpaSchemaExport.java:14)

edit: I do get warnings indeed:

:bignibou-server:JpaSchemaExport
2015-05-16 14:46:44,423 [main] WARN  org.hibernate.ejb.HibernatePersistence - HHH015016: Encountered a deprecated javax.persistence.spi.PersistenceProvider [org.hibernate.ejb.HibernatePersistence]; use [org.hibernate.jpa.HibernatePersistenceProvider] instead.
2015-05-16 14:46:44,423 [main] WARN  org.hibernate.ejb.HibernatePersistence - HHH015016: Encountered a deprecated javax.persistence.spi.PersistenceProvider [org.hibernate.ejb.HibernatePersistence]; use [org.hibernate.jpa.HibernatePersistenceProvider] instead.
2015-05-16 14:46:44,423 [main] WARN  org.hibernate.ejb.HibernatePersistence - HHH015016: Encountered a deprecated javax.persistence.spi.PersistenceProvider [org.hibernate.ejb.HibernatePersistence]; use [org.hibernate.jpa.HibernatePersistenceProvider] instead.
Exception in thread "main" javax.persistence.PersistenceException: No persistence provider found for schema generation for persistence-unit named default
 at javax.persistence.Persistence.generateSchema(Persistence.java:93)
 at com.bignibou.tools.jpa.JpaSchemaExport.execute(JpaSchemaExport.java:32)
 at com.bignibou.tools.jpa.JpaSchemaExport.main(JpaSchemaExport.java:14)
:bignibou-server:JpaSchemaExport FAILED 
Jarboe answered 13/5, 2015 at 21:5 Comment(7)
Looking at the AvailableSettings class, there is a PROVIDER constant, which according to docs is "The name of the PersistenceProvider implementor". So maybe you should set that property too. The value should be probably FQN of HibernatePersistenceProvider class, but unfortunately the docs are not clear on this ...Deva
Thanks. I have tried adding the following line: persistenceProperties.setProperty(AvailableSettings.PROVIDER, "org.hibernate.jpa.HibernatePersistenceProvider"); to no avail...Jarboe
Where is your persistence unit "default" defined?Protozoon
@andih: I use Spring Boot and I not defined any persistence unit name which seems to default to "default".Jarboe
the default PersistenceUnit according to the Documentation docs.spring.io/spring/docs/current/javadoc-api/org/…, also according to the JPA specification is none (empty). Try to set the PersistenceUnit emf. setPersistenceUnitName("default"); If "default" is the default name of the PersistenceUnit than this should not change anything, otherwise it defines a named PersistenceUnit with name "default" which you are already referencing.Protozoon
I've applied the suggested change and I get the same error as before. It is really as if my utility does not see my application's classes... It is therefore most probably a classpath issue related to my gradle config but I am not sure how to sort it...Jarboe
I implemented a similar thing, but ended extending javax.persistence.spi.PersistenceUnitInfo and then created emf like emf = new HibernatePersistenceProvider().createContainerEntityManagerFactory(puInfo, null);Kattegat
P
3

Your JpaSchemaExport is not executed within a Spring Context as far as I can see from your code.

When you run your JpaSchemaExport from Gradle or command line you create your own EntityManager which has nothing to do with Spring and looks for a persistence.xml file in the META-INF directory. For Spring Boot Applications this file is not needed and thus may not exist.

When I run something which looks similar your JpaSchemaExport the output is something like

[main] INFO  o.h.j.b.i.PersistenceXmlParser - HHH000318: Could not find any META-INF/persistence.xml file in the class path
[main] DEBUG o.h.jpa.HibernatePersistenceProvider - Located and parsed 0  persistence units; checking each 
[main] DEBUG o.h.jpa.HibernatePersistenceProvider - Found no matching persistence units Exception in thread "main"
javax.persistence.PersistenceException: No persistence provider found
for schema generation for persistence-unit named default    at
javax.persistence.Persistence.generateSchema(Persistence.java:93)   at
com.example.springboot.jpa.JpaSchemaExport.execute(JpaSchemaExport.java:42)
    at
com.example.springboot.jpa.JpaSchemaExport.main(JpaSchemaExport.java:14)

A Spring Boot Commandline Application (one that has a Spring Context) looks something like:

@SpringBootApplication
public class Application implements CommandLineRunner {


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

    @Override
    public void run(String... strings) throws Exception {

    }

}

i.e. your JpaSchemaExport may be rewritten as

@SpringBootApplication
public class JpaSchemaExport implements CommandLineRunner {


    public static void main(String[] args) {
        // maybe activate a special spring profile to enable 
        // "hibernate.hbm2ddl.auto", validate | update | create | create-drop
        // AvailableSettings.SCHEMA_GEN_DATABASE_ACTION, "none" 
        // AvailableSettings.SCHEMA_GEN_CREATE_SCHEMAS, "true"
        // AvailableSettings.SCHEMA_GEN_SCRIPTS_ACTION, "create"
        // AvailableSettings.SCHEMA_GEN_CREATE_SOURCE, "metadata"
        // AvailableSettings.SCHEMA_GEN_SCRIPTS_CREATE_TARGET, destination

        SpringApplication.run(JpaSchemaExport.class);
    }

    @Override
    public void run(String... strings) throws Exception {
       // nothing needed here 
    }

}

As an alternative you can create a META-INF/persistence.xml which can be used by your Spring Boot application as well as by your JpaSchemaExport.

Protozoon answered 17/5, 2015 at 15:6 Comment(0)
G
2

Your code is very good and clean. Is there any other warning on server startup like log4j properties missing .. etc.,

I think the problem is related to some missing jar or classpath entry, though not sure about it.

Graupel answered 16/5, 2015 at 11:12 Comment(1)
you're right. I am positive it is related to a classpath configuration issue. Any gradle user has any idea on how to sort this?Jarboe
P
2

It seems that Persistence.generateSchema() uses PersistenceProviderResolverHolder which holds a PersistenceProviderResolver to get a list of all available PersistenceProviders. Maybe you should try implementing your own PersistenceProviderResolver (only 2 methods) to return the one you want to use (org.hibernate.jpa.HibernatePersistenceProvider) before calling Persistence.generateSchema().

PersistenceProviderResolverHolder.setPersistenceProviderResolver(new PersistenceProviderResolver() {

    public List<PersistenceProvider> getPersistenceProviders() {
        return Collections.singletonList(new HibernatePersistenceProvider());
    }

    public void clearCachedProviders() {}
});
Penetration answered 21/5, 2015 at 13:46 Comment(0)
M
2

Generating schema with Spring Boot app:

import org.hibernate.jpa.AvailableSettings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import java.util.Properties;

@SpringBootApplication
public class JpaSchemaExport implements CommandLineRunner {
    @Autowired LocalContainerEntityManagerFactoryBean entityManagerFactory;

    public static void main(String... args) {
        new SpringApplicationBuilder(JpaSchemaExport.class).run(args);
    }

    @Override
    public void run(String... args) throws Exception {
        final Properties persistenceProperties = new Properties();

        // XXX force persistence properties : remove database target
        persistenceProperties.setProperty(org.hibernate.cfg.AvailableSettings.HBM2DDL_AUTO, "");
        persistenceProperties.setProperty(AvailableSettings.SCHEMA_GEN_DATABASE_ACTION, "none");

        // XXX force persistence properties : define create script target from metadata to destination
        persistenceProperties.setProperty(AvailableSettings.SCHEMA_GEN_CREATE_SCHEMAS, "true");
        persistenceProperties.setProperty(AvailableSettings.SCHEMA_GEN_SCRIPTS_ACTION, "create");
        persistenceProperties.setProperty(AvailableSettings.SCHEMA_GEN_CREATE_SOURCE, "metadata");
        persistenceProperties.setProperty(AvailableSettings.SCHEMA_GEN_SCRIPTS_CREATE_TARGET, "./generated-schema.ddl");

        // generate sql with semicolon - workaround for HHH-10278
        String systemLineSeparator = System.getProperty("line.separator");
        System.setProperty("line.separator", ';' + systemLineSeparator);
        // get a persistence provider from spring context
        entityManagerFactory.getJpaVendorAdapter().getPersistenceProvider().generateSchema(entityManagerFactory.getPersistenceUnitInfo(), persistenceProperties);

        System.setProperty("line.separator", systemLineSeparator);
        System.exit(0);
    }

}
Mccloud answered 6/2, 2017 at 4:55 Comment(0)
G
1

You would need to set an explicit name for the persistence unit that is created programmatically using the following method and then make sure to call the afterPropertiesSet() method:

emf.setPersistenceUnitName( "puname" );
...
emf.afterPropertiesSet();

Refer to your persistence unit using this name instead of "default"

Gerhan answered 21/5, 2015 at 20:30 Comment(0)
S
1

If I don't use META-INF/persistence.xml, persistence-unit is not found by its name.

I had to inject the EntityManagerFactory:

@Autowired private LocalContainerEntityManagerFactoryBean emf;

... and find the persistence-unit by the info object:

PersistenceProvider provider = emf.getJpaVendorAdapter().getPersistenceProvider();
provider.generateSchema(emf.getPersistenceUnitInfo(), persistenceProperties);

This worked for me. I hope it could help someone else too.

Stripling answered 24/5, 2021 at 6:14 Comment(1)
Thanks this worked for me to, creating a unit test to find out db changes between versions without using flyway or dbmaintainPyrrhonism

© 2022 - 2024 — McMap. All rights reserved.