javahibernatejpaentitymanagerjpa-2.1

EntityManager provider not found


I used hibernate EntityManager on standalone application (Without framework) .

this is my pom.xml :

<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>ir.moke.roboexchange</groupId>
    <artifactId>roboexchange</artifactId>
    <version>1.0-SNAPSHOT</version>
    <organization>
        <name>Moke</name>
        <url>http://www.moke.ir</url>
    </organization>

    <name>Moke :: RoboExchange</name>

    <properties>
        <junit.jupiter.version>5.9.2</junit.jupiter.version>
        <junit.platform.version>1.9.2</junit.platform.version>
    </properties>

    <packaging>jar</packaging>

    <dependencies>
        <!-- ORM -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>6.6.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate.orm</groupId>
            <artifactId>hibernate-ant</artifactId>
            <version>6.6.0.Final</version>
        </dependency>

        <!-- Json -->
        <dependency>
            <groupId>org.eclipse</groupId>
            <artifactId>yasson</artifactId>
            <version>3.0.2</version>
        </dependency>

        <!-- Database -->
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>42.5.4</version>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>4.3.1</version>
        </dependency>

        <!-- Log -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>2.0.5</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.4.6</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>1.4.6</version>
        </dependency>

        <!-- Test -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>${junit.jupiter.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>${junit.jupiter.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-params</artifactId>
            <version>${junit.jupiter.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-suite</artifactId>
            <version>${junit.platform.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <finalName>roboexchange</finalName>
        <plugins>
            <!-- Java compiler version -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <release>17</release>
                </configuration>
            </plugin>

            <!-- copy compiled jar file to target/lib -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.2.2</version>
                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <mainClass>ir.moke.roboexchange.MainClass</mainClass>
                        </manifest>
                    </archive>
                    <outputDirectory>${project.build.directory}/lib/</outputDirectory>
                </configuration>
            </plugin>

            <!-- Copy dependencies -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy-dependencies</id>
                        <phase>package</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${project.build.directory}/lib</outputDirectory>
                            <includeScope>compile</includeScope>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

and this is my persistence.xml :

<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
             http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
             version="2.1">
    <persistence-unit name="db-connection" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
    </persistence-unit>

</persistence>

I have a class named EntityManagerProducer :

import ir.moke.roboexchange.config.Configuration;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;

import java.util.HashMap;
import java.util.Map;

public class EntityManagerProducer {
    public static final EntityManagerProducer instance = new EntityManagerProducer();
    private final EntityManagerFactory entityManagerFactory;
    private final EntityManager entityManager;

    private EntityManagerProducer() {
        String hostname = Configuration.dbHost;
        String port = Configuration.dbPort;
        String username = Configuration.dbUsername;
        String password = Configuration.dbPassword;

        Map<String, Object> properties = new HashMap<>();
        properties.put("hibernate.connection.driver_class", "org.postgresql.Driver");
        properties.put("hibernate.connection.url", "jdbc:postgresql://%s:%s/roboexchange".formatted(hostname, port));
        properties.put("hibernate.connection.username", username);
        properties.put("hibernate.connection.password", password);
        properties.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
        this.entityManagerFactory = Persistence.createEntityManagerFactory("db-connection", properties);
        this.entityManager = this.entityManagerFactory.createEntityManager();
    }

    public EntityManager getEntityManager() {
        return entityManager;
    }

    public EntityManagerFactory getEntityManagerFactory() {
        return entityManagerFactory;
    }
}

this is my example CRUD :

public class SampleCRUD {
    private static final EntityManager em = EntityManagerProducer.instance.getEntityManager();

    public static void insert(Sample sample) {
        EntityTransaction transaction = em.getTransaction();
        transaction.begin();
        em.persist(sample);
        transaction.commit();
    }
}

My main class work with Intellij IDEA without any problem .

but when i export project as jar file and run that , result this exception :

Aug 22, 2024 8:40:24 PM jakarta.persistence.spi.PersistenceProviderResolverHolder$DefaultPersistenceProviderResolver log
WARNING: jakarta.persistence.spi::No valid providers found.
Exception in thread "Timer-0" java.lang.ExceptionInInitializerError
        at ir.moke.roboexchange.strategy.StrategyManager.<clinit>(StrategyManager.java:22)
        at ir.moke.roboexchange.job.FetchStatistics_5Min.run(FetchStatistics_5Min.java:20)
        at java.base/java.util.TimerThread.mainLoop(Timer.java:566)
        at java.base/java.util.TimerThread.run(Timer.java:516)
Caused by: jakarta.persistence.PersistenceException: No Persistence provider for EntityManager named db-connection
        at jakarta.persistence.Persistence.createEntityManagerFactory(Persistence.java:86)
        at ir.moke.roboexchange.producer.EntityManagerProducer.<init>(EntityManagerProducer.java:28)
        at ir.moke.roboexchange.producer.EntityManagerProducer.<clinit>(EntityManagerProducer.java:12)
        ... 4 more

Note : persistence.xml inside jar file is under META-INF directory
Note : I mixed persistence.xml and programmatically class, because configuration dynamically maybe changed.


Update:

Run application :

> mvn clean compile package 
> cd target/lib 
> java -jar roboexchange.jar   
11:12:21,734 |-INFO in ch.qos.logback.core.model.processor.AppenderModelHandler - About to instantiate appender of type [ch.qos.logback.core.ConsoleAppender]
11:12:21,769 |-WARN in ch.qos.logback.core.ConsoleAppender[CONSOLE] - This appender no longer admits a layout as a sub-component, set an encoder instead.
11:12:21,769 |-WARN in ch.qos.logback.core.ConsoleAppender[CONSOLE] - To ensure compatibility, wrapping your layout in LayoutWrappingEncoder.
11:12:21,769 |-WARN in ch.qos.logback.core.ConsoleAppender[CONSOLE] - See also http://logback.qos.ch/codes.html#layoutInsteadOfEncoder for details
11:12:21,769 |-WARN in ch.qos.logback.core.model.processor.AppenderModelHandler - Appender named [FILE-ROLLING] not referenced. Skipping further processing.
11:12:21,770 |-INFO in ch.qos.logback.classic.model.processor.LoggerModelHandler - Setting level of logger [org.hibernate] to INFO
11:12:21,774 |-INFO in ch.qos.logback.classic.model.processor.LoggerModelHandler - Setting additivity of logger [org.hibernate] to false
11:12:21,775 |-INFO in ch.qos.logback.core.model.processor.AppenderRefModelHandler - Attaching appender named [CONSOLE] to Logger[org.hibernate]
11:12:21,775 |-INFO in ch.qos.logback.classic.model.processor.LoggerModelHandler - Setting level of logger [ir.moke.roboexchange] to DEBUG
11:12:21,775 |-INFO in ch.qos.logback.classic.model.processor.LoggerModelHandler - Setting additivity of logger [ir.moke.roboexchange] to false
11:12:21,775 |-INFO in ch.qos.logback.core.model.processor.AppenderRefModelHandler - Attaching appender named [CONSOLE] to Logger[ir.moke.roboexchange]
11:12:21,775 |-INFO in ch.qos.logback.classic.model.processor.RootLoggerModelHandler - Setting level of ROOT logger to ALL
11:12:21,776 |-INFO in ch.qos.logback.core.model.processor.AppenderRefModelHandler - Attaching appender named [CONSOLE] to Logger[ROOT]
11:12:21,776 |-INFO in ch.qos.logback.core.model.processor.DefaultProcessor@33cb5951 - End of configuration.
11:12:21,776 |-INFO in ch.qos.logback.classic.joran.JoranConfigurator@365c30cc - Registering current configuration as safe fallback point 
... 
...
...
...... and other logs ..... 
...
...

Aug 22, 2024 8:40:24 PM jakarta.persistence.spi.PersistenceProviderResolverHolder$DefaultPersistenceProviderResolver log
WARNING: jakarta.persistence.spi::No valid providers found.
Exception in thread "Timer-0" java.lang.ExceptionInInitializerError
        at ir.moke.roboexchange.strategy.StrategyManager.<clinit>(StrategyManager.java:22)
        at ir.moke.roboexchange.job.FetchStatistics_5Min.run(FetchStatistics_5Min.java:20)
        at java.base/java.util.TimerThread.mainLoop(Timer.java:566)
        at java.base/java.util.TimerThread.run(Timer.java:516)
Caused by: jakarta.persistence.PersistenceException: No Persistence provider for EntityManager named db-connection
        at jakarta.persistence.Persistence.createEntityManagerFactory(Persistence.java:86)
        at ir.moke.roboexchange.producer.EntityManagerProducer.<init>(EntityManagerProducer.java:28)
        at ir.moke.roboexchange.producer.EntityManagerProducer.<clinit>(EntityManagerProducer.java:12)
        ... 4 more   

this is content of MANIFEST.MF inside jar file :

Manifest-Version: 1.0
Created-By: Maven JAR Plugin 3.2.2
Build-Jdk-Spec: 21
Class-Path: hibernate-core-6.6.0.Final.jar jakarta.persistence-api-3.1.0
 .jar jakarta.transaction-api-2.0.1.jar jboss-logging-3.5.0.Final.jar hi
 bernate-commons-annotations-7.0.1.Final.jar jandex-3.2.0.jar classmate-
 1.5.1.jar byte-buddy-1.14.18.jar jakarta.xml.bind-api-4.0.0.jar jakarta
 .activation-api-2.1.0.jar jaxb-runtime-4.0.2.jar jaxb-core-4.0.2.jar an
 gus-activation-2.0.0.jar txw2-4.0.2.jar istack-commons-runtime-4.1.1.ja
 r jakarta.inject-api-2.0.1.jar antlr4-runtime-4.13.0.jar hibernate-ant-
 6.6.0.Final.jar yasson-3.0.2.jar jakarta.json.bind-api-3.0.0.jar jakart
 a.json-api-2.1.0.jar parsson-1.1.0.jar postgresql-42.5.4.jar checker-qu
 al-3.5.0.jar jedis-4.3.1.jar commons-pool2-2.11.1.jar json-20220320.jar
  gson-2.8.9.jar slf4j-api-2.0.5.jar logback-classic-1.4.6.jar logback-c
 ore-1.4.6.jar
Main-Class: ir.moke.roboexchange.MainClass


Solution

  • I finally fixed my problem .
    maven-dependency-plugin should be configured like this :

                <!-- Copy dependencies -->
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-dependency-plugin</artifactId>
                    <executions>
                        <execution>
                            <id>copy-dependencies</id>
                            <phase>package</phase>
                            <goals>
                                <goal>copy-dependencies</goal>
                            </goals>
                            <configuration>
                                <outputDirectory>${project.build.directory}/lib</outputDirectory>
                                <includeScope>runtime</includeScope>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
    

    Note: Should config to copy runtime dependencies