1

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?

Kleber Mota
  • 8,521
  • 31
  • 94
  • 188

1 Answers1

1

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.

jccampanero
  • 50,989
  • 3
  • 20
  • 49
  • Using the mentioned libraries, is it possible create this configuration with java code instead of the xml file "persistence.xml"? – Kleber Mota Jul 30 '23 at 22:35
  • Thank you for the feedback @KleberMota. Well, I never tested myself, but you could try something like the [following example](https://vladmihalcea.com/how-to-bootstrap-jpa-programmatically-without-the-persistence-xml-configuration-file/) from Vlad Mihalcea: it is Hibernate specific, but I think it could be of help. In any case, it is possible, at least override properties - although I am afraid not the provider itself - for instance, some frameworks such as Spring allows you to override some configuration properties: I will dig into it in the Spring specific use case. – jccampanero Jul 30 '23 at 22:59
  • Can you tell where to put the file "persistence.xml", if I decide to use this approach? I have tried put in the directory `src/main/resources/META-INF/persistence.xml` as suggested in the post, but it seems that is not working, since `@PersistenceUnit(name = "default") private EntityManagerFactory entityManagerFactory;` is getting null. – Kleber Mota Jul 30 '23 at 23:14
  • Thank you very much for the feedback again @KleberMota. Sorry for the late reply. Yes, it is the right location for `persistence.xml`. The problem is that in order to use `@PersistenceUnit` you need some type of DI mechanism such as Spring or CDI; on the contrary, you need to setup your `EntityManagerFactory` manually. I updated my answer trying to clarifying both things, I hope it helps. – jccampanero Jul 31 '23 at 09:50
  • I got the same issue when using `EntityManagerFactory factory = Persistence.createEntityManagerFactory("default"); EntityManager em = factory.createEntityManager();` and I am using Maven like the answer suggests. – Kleber Mota Jul 31 '23 at 21:00
  • Thank you @KleberMota. It is strange indeed. Please, could you update your answer with the `persistence.xml` file that you are using? Did you included the required JPA provider libraries in your Maven dependencies? – jccampanero Jul 31 '23 at 21:44
  • that's what my project structure and pom.xml looks like right now: https://imgur.com/a/0Nn22V5 – Kleber Mota Jul 31 '23 at 22:01
  • You are using the latest version of `eclipselink`. Please, can you remove the `javax.persistence` dependency in your `pom.xml` and include the [jakarta based one](https://mvnrepository.com/artifact/jakarta.persistence/jakarta.persistence-api/3.1.0) - in fact it should be already included as a dependency of `eclipselink`? Please, could you share your `persistence.xml` file as well? Probably you need to use the new XSD and property names in the Jakarta namespace. Please, see [this related SO question](https://stackoverflow.com/a/72860543/13942448) for reference. – jccampanero Jul 31 '23 at 22:20
  • Please, consider review [this post](https://blog.jetbrains.com/idea/2021/02/creating-a-simple-jakarta-persistence-application/) regarding the new Jakarta JPA persistence version: I was searching for information for trying helping you and I came across it, it is for hsqldb but I think it could be of help. Please, note that you will need to update the imports in your code as well to, for instance, `jakarta.persistence.EntityManagerFactory`. Note the `jakarta.persistence` package. – jccampanero Jul 31 '23 at 22:34
  • Yes, that worked, but now I am getting the error `Caused by: java.sql.SQLException: opening db: '../data.db': Read-only file system` (the data.db file is located on the directory `src/main/resources` of my project, and the war file is deployed automatically by tomcat when I copy it in the directory `/var/lib/tomcat/webapps` (a directory `auth` is created with owner the user `tomcat` with the permissions: `drwxr-x---`) – Kleber Mota Jul 31 '23 at 23:46
  • Sorry for the late reply @KleberMota. I am happy to hear that the issue was solved. Regarding the new problem, I think it could be motivated because you are probably trying to write to the SQLite database, but it is contained in the jar file, and I think it could be the reason for the read-only filesystem message. You usually embed the sqlite db file in a jar when, for instance, it stores some type of configuration that need only to read. If you require a database for writing I would recommend creating the db file in the server filesystem instead. In addition, it will allow you to reuse the – jccampanero Aug 02 '23 at 15:56
  • information stored in the database across application restarts. – jccampanero Aug 02 '23 at 15:57