javajava-8h2payara-micro

Payara Micro ignoring connection url in persistence.xml


I am writing a Payara Micro web application that should connect to a database as defined in persistence.xml. The database it should connect to is a file on my local machine and at the time of project startup, it does not exist. To my understanding, H2 should create a file for the database on first connect.

The persistence.xml looks like:

<?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="com.danjbower_h2test_war_0.0.1PU"
                      transaction-type="JTA">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>

        <class>com.danjbower.h2test.Test</class>

        <properties>
            <property name="hibernate.connection.driver_class" value="org.h2.Driver" />
            <property name="hibernate.connection.url" value="jdbc:h2:file:C:/databases/testdb" />
            <property name="hibernate.connection.username" value="sa" />
            <property name="hibernate.connection.password" value="" />

            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.format_sql" value="true" />
            <property name="hibernate.hbm2ddl.auto" value="update" />
            <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
            <property name="hibernate.temp.use_jdbc_metadata_defaults" value="false" />
            <property name="hibernate.transaction.jta.platform" value="SunOne" />
        </properties>
    </persistence-unit>
</persistence>

When the project is running it connects to a database and runs sql commands to create tables and add a specific entity I want adding defined in a startup bean. However, when I check my system it has not created a C:\databases\testdb.mv.db file as I would have expected. What is going wrong and how can I make it so it actually generates the database file rather than seemingly ignoring the configuration?


Additional files for MCVE

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.danjbower</groupId>
    <artifactId>H2Test</artifactId>
    <version>0.0.1</version>
    <packaging>war</packaging>

    <name>H2Test</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <failOnMissingWebXml>false</failOnMissingWebXml>
        <version.payara>5.201</version.payara>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>fish.payara.api</groupId>
                <artifactId>payara-bom</artifactId>
                <version>${version.payara}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>jakarta.platform</groupId>
            <artifactId>jakarta.jakartaee-web-api</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>jakarta.enterprise.concurrent</groupId>
            <artifactId>jakarta.enterprise.concurrent-api</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>jakarta.resource</groupId>
            <artifactId>jakarta.resource-api</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>jakarta.batch</groupId>
            <artifactId>jakarta.batch-api</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.eclipse.microprofile</groupId>
            <artifactId>microprofile</artifactId>
            <scope>provided</scope>
            <type>pom</type>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>5.4.25.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>5.4.25.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate.javax.persistence</groupId>
            <artifactId>hibernate-jpa-2.1-api</artifactId>
            <version>1.0.2.Final</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>fish.payara.maven.plugins</groupId>
                <artifactId>payara-micro-maven-plugin</artifactId>
                <version>1.0.6</version>
                <configuration>
                    <payaraVersion>${version.payara}</payaraVersion>
                    <deployWar>false</deployWar>
                    <commandLineOptions>
                        <option>
                            <key>--autoBindHttp</key>
                        </option>
                        <option>
                            <key>--deploy</key>
                            <value>${project.build.directory}/${project.build.finalName}</value>
                        </option>
                    </commandLineOptions>
                    <contextRoot>/H2Test</contextRoot>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>payara-patched-externals</id>
            <name>Payara Patched Externals</name>
            <url>https://raw.github.com/payara/Payara_PatchedProjects/master</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

</project>

Test.java

package com.danjbower.h2test;

import java.util.Objects;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import javax.xml.bind.annotation.XmlRootElement;

@Entity
@Table(name = "Tests")
@XmlRootElement
public class Test
{
    @Id
    @Column(name = "Id", unique = true)
    @Basic(optional = false)
    @NotNull
    private Integer id = 0;

    public Integer getId()
    {
        return id;
    }

    public void setId(Integer id)
    {
        this.id = id;
    }

    @Override
    public int hashCode()
    {
        return id;
    }

    @Override
    public boolean equals(Object obj)
    {
        if (this == obj)
        {
            return true;
        }

        if (obj == null)
        {
            return false;
        }

        if (getClass() != obj.getClass())
        {
            return false;
        }

        final Test other = (Test) obj;

        return Objects.equals(id, other.id);
    }

    @Override
    public String toString()
    {
        return "Test (Id: " + id + ")";
    }
}

StartUp.java

package com.danjbower.h2test;

import javax.annotation.PostConstruct;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Startup
@Singleton
public class StartUp
{
    @PersistenceContext(unitName = "com.danjbower_h2test_war_0.0.1PU")
    private EntityManager entityManager;

    @PostConstruct
    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void init()
    {
        Test test = new Test();
        test.setId(4);
        entityManager.persist(test);
    }
}

Log showing it running commands

Hibernate: 
    
    create table Tests (
       Id integer not null,
        primary key (Id)
    )

Hibernate: 
    insert 
    into
        Tests
        (Id) 
    values
        (?)


[2021-03-07T03:37:03.511+0000] [] [INFO] [] [PayaraMicro] [tid: _ThreadID=1 _ThreadName=main] [timeMillis: 1615088223511] [levelValue: 800] 
{
    "Instance Configuration": {
        "Host": "192.168.1.12",
        "Http Port(s)": "8080",
        "Https Port(s)": "",
        "Instance Name": "Hilarious-Boxfish",
        "Instance Group": "MicroShoal",
        "Hazelcast Member UUID": "ae8dbc3a-b361-4dd6-bbba-762e620f96a8",
        "Deployed": [
            {
                "Name": "H2Test-0.0.1",
                "Type": "war",
                "Context Root": "/H2Test"
            }
        ]
    }
}

[2021-03-07T03:37:03.513+0000] [] [INFO] [] [PayaraMicro] [tid: _ThreadID=1 _ThreadName=main] [timeMillis: 1615088223513] [levelValue: 800] 
Payara Micro URLs:
http://192.168.1.12:8080/H2Test

Solution

  • A working example of the project can be found here github.com/DanJBower/H2Test.


    One solution to this problem is to set up a jta-data-source instead of using hibernate.connection.* properties.

    This meant changing persistence.xml to

    <?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="com.danjbower_h2test_war_0.0.1PU"
                          transaction-type="JTA">
            <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
    
            <jta-data-source>java:app/TestDb</jta-data-source>
            <exclude-unlisted-classes>false</exclude-unlisted-classes>
    
            <properties>
                <property name="hibernate.show_sql" value="true" />
                <property name="hibernate.format_sql" value="true" />
                <property name="hibernate.hbm2ddl.auto" value="update" />
                <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
                <property name="hibernate.transaction.jta.platform" value="SunOne" />
            </properties>
        </persistence-unit>
    </persistence>
    

    and adding a file called payara-resources.xml. This is where the database connection is set up.

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE resources PUBLIC "-//Payara.fish//DTD Payara Server 4 Resource Definitions//EN" "https://raw.githubusercontent.com/payara/Payara-Community-Documentation/master/docs/modules/ROOT/pages/schemas/payara-resources_1_6.dtd">
    <resources>
        <jdbc-resource pool-name="TestDb"
                       jndi-name="java:app/TestDb"
                       enabled="true" />
    
        <jdbc-connection-pool datasource-classname="org.h2.jdbcx.JdbcDataSource"
                              name="TestDb"
                              res-type="javax.sql.DataSource">
            <property name="URL" value="jdbc:h2:file:C:/databases/TestDb" />
            <property name="User" value="sa" />
            <property name="Password" value="" />
        </jdbc-connection-pool>
    </resources>
    

    Note

    Originally I put this in web.xml as

    <data-source>
        <name>java:app/TestDb</name>
        <class-name>org.h2.Driver</class-name>
        <url>jdbc:h2:file:C:/databases/TestDb</url>
        <user>sa</user>
        <password></password>
    </data-source>
    

    However, when doing this I came across an error where it said there was no password set. Very similar to this issue.