0

I am trying to add JPA to my project, but always getting those errors:

keycloak_1   | 17:28:43,494 INFO  [org.hibernate.jpa.boot.internal.PersistenceXmlParser] (default task-2) HHH000318: Could not find any META-INF/persistence.xml file in the classpath
keycloak_1   | 17:28:43,495 ERROR [org.keycloak.services.error.KeycloakErrorHandler] (default task-2) Uncaught server error: javax.persistence.PersistenceException: No Persistence provider for EntityManager named SQL

But when i try to initialise my entity manager:

HashMap<String, String> properties = new HashMap<>();
properties.put("javax.persistence.jdbc.driver", configMap.getFirst(CONFIG_KEY_JDBC_URL));
properties.put("javax.persistence.jdbc.url", configMap.getFirst(CONFIG_KEY_JDBC_URL));
properties.put("javax.persistence.jdbc.user", configMap.getFirst(CONFIG_KEY_DB_USERNAME));
properties.put("javax.persistence.jdbc.password", configMap.getFirst(CONFIG_KEY_DB_PASSWORD));

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

EntityManager entityManager = entityManagerFactory.createEntityManager();

I am receiving those errors, but i can't understand how it's possible then i am clearly added that file to my .jar.

Persistence.xml content is :

<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd"
             version="2.2">
    <persistence-unit name="SQL" transaction-type="RESOURCE_LOCAL">
        <properties>
            <property name="javax.persistence.jdbc.driver" value=""/>
            <property name="javax.persistence.jdbc.url" value=""/>
            <property name="javax.persistence.jdbc.user" value=""/>
            <property name="javax.persistence.jdbc.password" value=""/>
        </properties>
    </persistence-unit>
</persistence>

Structure of project and compiled jar is visible here (persistence content is changed to 2.2 version to mentioned before):

enter image description here

What am i doing wrong?

Update: Even find command returns that file exists in a correct directory:

➜  sql-sync-spi find . -type f -name "persistence.xml"
./build/resources/main/META-INF/persistence.xml
./src/main/resources/META-INF/persistence.xml

More updates: I've tried to copy persistence.xml from another project:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
             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">
    <persistence-unit name="user-storage-jpa-example">
        <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>

        <class>org.keycloak.quickstart.storage.user.UserEntity</class>

        <properties>
            <property name="hibernate.hbm2ddl.auto" value="update" />
            <property name="hibernate.show_sql" value="false" />
        </properties>
    </persistence-unit>
</persistence>

And on service startup i've received fatal error:

07:03:02,188 ERROR [org.jboss.as.controller.management-operation] (Controller Boot Thread) WFLYCTL0013: Operation ("deploy") failed - address: ([("deployment" => "sql-sync-spi-1.0-SNAPSHOT.jar")]) - failure description: {
    "WFLYCTL0412: Required services that are not installed:" => ["jboss.naming.context.java.jboss.datasources.ExampleDS1"],
    "WFLYCTL0180: Services with missing/unavailable dependencies" => [
        "jboss.persistenceunit.\"sql-sync-spi-1.0-SNAPSHOT.jar#sql\".__FIRST_PHASE__ is missing [jboss.naming.context.java.jboss.datasources.ExampleDS]",
        "jboss.persistenceunit.\"sql-sync-spi-1.0-SNAPSHOT.jar#sql\" is missing [jboss.naming.context.java.jboss.datasources.ExampleDS1]"
    ]
}

So at least part of the project sure sees persistence.xml file and tries to read it. Then i've changed xml back to my settings, and again i have no error on startup but again no file exists in classpath on entity manager init attempt.

Itsmeromka
  • 3,621
  • 9
  • 46
  • 79
  • 1. So it also is in the built jar (open the jar itself, 7zip or such)? 2. I assume you cleared the `value` attributes here (as one should!). – Joop Eggen Aug 15 '21 at 20:35
  • Yes, if i "unzip" `sql-sync-spi-1.0-SNAPSHOT.jar` to `sql-sync-spi-1.0-SNAPSHOT` folder, then i can find persistence.xml in `sql-sync-spi-1.0-SNAPSHOT/META-INF/persistence.xml` (with find command, to ignore human mistake) – Itsmeromka Aug 15 '21 at 20:51
  • 1
    IIUC, a Keycloak server is really just a WildFly server. [This project](https://github.com/keycloak/keycloak-quickstarts/tree/latest/user-storage-jpa) seems to be very similar to yours, only it uses Maven config. Note how dependencies are listed in `pom.xml`. The scope is `provided`. That's because the keycloak runtime *provides* them. In order to do the same with Gradle, see: https://stackoverflow.com/questions/18738888/how-to-use-provided-scope-for-jar-file-in-gradle-build – Janez Kuhar Aug 15 '21 at 21:50
  • Yeap, i am actually copying many ideas from here, but stuck on adding entity manager because of persistance.xml problem. – Itsmeromka Aug 15 '21 at 21:51
  • @JanezKuhar sadly your mentioned solution didn't help, it says to use "compileOnly group" when you are using "provided" scope, i've tried that and no luck. – Itsmeromka Aug 16 '21 at 06:45
  • 1
    Have you been able to resolve the problem? – Janez Kuhar Aug 17 '21 at 21:16

1 Answers1

1

This is more of a comment than an answer since there's not enough room in the comment section and I haven't verified any of this.

First of all, I'd define a new DataSource on your Keycloak server. See: Relational Database Setup.

Your dependencies section of build.gradle should then look somewhat similar to:

dependencies {
    compileOnly 'org.keycloak:keycloak-server-spi'
    compileOnly 'org.keycloak:keycloak-common'
    implementation 'org.apache.commons:commons-lang3:3.12.0'
    compileOnly 'org.hibernate.javax.persistance:hibernate-jpa-2.1-api:1.0.0.Final'
    compileOnly 'org.jboss.spec.javax.ejb:jboss-ejb-api_3.2_spec:1.0.0.Final'

    compileOnly platform('org.wildfly.bom:wildfly-javaee8:14.0.1.Final')
    compileOnly platform('org.keycloak.bom:keycloak-spi-bom:15.0.1')
}

Your persistence.xml should change since we defined a DataSource on Keycloak:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
    xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="yourDataSource">
        <jta-data-source>your_DS_name</jta-data-source>
        <!-- List your entities here. For example: -->
        <class>com.rmndbrvn.sqlsyncspi.UserEntity</class>
    </persistence-unit>
</persistence>

You can then get an instance to an EntityManager in your code like this:

@PersistenceContext(unitName = "yourDataSource")
EntityManager em;
Janez Kuhar
  • 3,705
  • 4
  • 22
  • 45