Search code examples
javapersistencedaoentitymanagerentitymanagerfactory

How to define a persistenceprovider for a getEntityManager method?


I am trying implement a template for my Model classes in my java/servlet project, with methods for create tables, insert, update, delete and select data. the start point for all this methods is this method protected EntityManager getEntityManager() where I define where the sqlite database is located and other preferences.

But when this method is executed, the error javax.persistence.PersistenceException: No Persistence provider for EntityManager named default happens. My current implementation for this method is:

public abstract class Dao<E extends Model> {
    private Class<E> classe;

    public Dao(Class<E> classe) {
        this.classe = classe;
        if(!exists()) create();
    }

protected EntityManager getEntityManager() {
    String url = getClass().getResource("/data.db").toString();
    Map<String, String> properties = new HashMap<>();
    properties.put("javax.persistence.jdbc.provider", "org.eclipse.persistence.jpa.PersistenceProvider");
    properties.put("javax.persistence.jdbc.driver", "org.sqlite.JDBC");
    properties.put("javax.persistence.jdbc.url", "jdbc:sqlite:"+url);
    EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("default", properties);
    return entityManagerFactory.createEntityManager();
}

    ...
}

anyone knows how to solve this, without have to include an external library like hibernate or similar?


Solution

  • The error you are facing:

    javax.persistence.PersistenceException: No Persistence provider for EntityManager named default
    

    is raised when you are trying creating the EntityManagerFactory in this line of code:

    EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("default", properties);
    

    Under the hood, this method will invoke the configured PersistenceProvider but according to the error either no one is configured or there is some type of misconfiguration.

    A PersistenceProvider is configured when defining your application JPA persistence unit. For this purpose you need to define an appropriate persistence.xml file (please, consider read for example this related article of Vlad Mihalcea).

    The content of this file will depend on the actual JPA implementation library that you are using, although it will be the same in a great extend.

    For example, consider review the configuration provided for Hibernate in this gist:

    <persistence xmlns="http://java.sun.com/xml/ns/persistence"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
                 version="2.0">
    
        <persistence-unit name="sample">
            <provider>org.hibernate.ejb.HibernatePersistence</provider>
            <class>org.sample.entities.Entity</class>
    
            <properties>
                <property name="dialect" value="org.hibernate.dialect.SQLiteDialect" />
                <property name="javax.persistence.jdbc.driver" value="org.sqlite.JDBC" />
                <property name="javax.persistence.jdbc.url" value="jdbc:sqlite::memory:" />
                <property name="javax.persistence.jdbc.user" value="" />
                <property name="javax.persistence.jdbc.password" value="" />
                <property name="hibernate.show_sql" value="true" />
                <property name="format_sql" value="true" />
                <property name="hibernate.connection.charSet" value="UTF-8" />
                <property name="hibernate.hbm2ddl.auto" value="create" />
            </properties>
        </persistence-unit>
    </persistence>
    

    For EclipseLink, as in your example, I came across this excellent example:

    <?xml version="1.0" encoding="UTF-8" ?>
    <persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
        version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">
     
        <!-- Persistence Provider -->
        <!-- RESOURCE-LOCAL: Application-managed transactions -->
        <!-- JTA: Container-managed transactions -->
        <persistence-unit name="company-provider" transaction-type="RESOURCE_LOCAL">
            <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
     
            <!-- Entity Class -->
            <class>sample.db.pojos.Employee</class>
            <class>sample.db.pojos.Department</class>
            <class>sample.db.pojos.Report</class>
     
            <properties>    
                <!-- Connection properties -->
                <property name="javax.persistence.jdbc.driver" value="org.sqlite.JDBC" />
                <property name="javax.persistence.jdbc.url" value="jdbc:sqlite:./db/company.db" />
                <!-- Fill if we need user and password -->
                <property name="javax.persistence.jdbc.user" value="" />
                <property name="javax.persistence.jdbc.password" value="" />
                
                <!-- Controls logging level -->
                <property name="eclipselink.logging.level" value="INFO" />
                <!-- <property name="eclipselink.logging.level" value="ALL" /> -->
    
                <!-- JPA doesn't create the schema -->
                <property name="eclipselink.ddl-generation" value="create-tables" />
                <!-- JPA destroys and recreates the schema -->
                <!-- <property name="eclipselink.ddl-generation" value="drop-and-create-tables" /> -->
            </properties>
     
        </persistence-unit>
    </persistence>
    

    Please, note that in any case the persistence unit name should be the one you configured, default:

    persistence-unit name="default"
    

    The persistence.xml usually must be defined in the META-INF directory, i.e., if you are using Maven standard layout, in src/main/resources/META-INF/persistence.xml.

    With this configuration in place, you can create the EntityManagerFactory manually with the following code:

    EntityManagerFactory factory = Persistence.createEntityManagerFactory("default");
    EntityManager em = factory.createEntityManager();
    

    Regarding your comments, please, note that unless you are using some type of dependency injection mechanism - Spring, CDI - you will not be able to use the @PersistenceUnit annotation (please, see this related SO question): as stated, you need to create the EntityManagerFactory manually as described above.

    One of the above mentioned repositories provides a more complete example.

    You need to include the required dependencies, Hibernate or EcliseLink, in your project; I am aware that you mentioned if anybody knows how to do that without those libraries but, and I hope to be wrong, I think that the task of implementing a custom PersistenceProvider could be cornerstone. Please, take into account that you will need to implement, among other things, the EntityManager itself, model all the transitions between the different persistent states of the entity, etc. Please, prefer instead a battle tested solution based on any of the two libraries mentioned.