Red Hat

In Relation To Vlad Mihalcea

In Relation To Vlad Mihalcea

JPA test case templates

Posted by    |       |    Tagged as Hibernate ORM

In the good spirit of open source, any Hibernate ORM issue should be accompanied by a replicating test case. The test case is a proof that the issue really exists and is reproducible.

To simplify the test case writing procedure, Hibernate provides a series of templates that you can just grab from GitHub. Thanks to these tests, the issue reporter can focus on the actual persistence-related problem since the templates take care of all the bootstrapping logic.

Previously, the test case templates were available only for the Hibernate native API, which was fine as long as you’re familiar with it. Because many projects use Hibernate as a JPA provider, it’s very convenient to offer a JPA bootstrap environment as well. And that’s what we did.

Next, I’m going to provide a step-by-step guide for writing a JPA-based Hibernate test case.

First, you need to either fork or download the hibernate-test-case-templates GitHub repository.

This repository has an orm folder containing two Maven modules:

hibernate-orm-4

To replicate issues for Hibernate 4.x

hibernate-orm-5

To replicate issues for Hibernate 5.x

Each module has three templates:

ORMStandaloneTestCase.java

This one is a Hibernate native test case (you get access to the SessionFactory and you operate with a Session), but it requires you to manually bootstrap the Hibernate environment.

ORMUnitTestCase.java

This is also a Hibernate native test case (you get access to the SessionFactory and you operate with a Session), but the bootstrapping is provided on your behalf.

JPAUnitTestCase.java

This is the new template that needs to be used for replicating an issue using the Java Persistence API (you get access to the EntityManagerFactory and you operate with an EntityManager).

When replicating an issue with the Hibernate native API, the ORMUnitTestCase is usually preferred.

This post focuses on the newly added JPAUnitTestCase which looks like this:

public class JPAUnitTestCase {

    private EntityManagerFactory entityManagerFactory;

    @Before
    public void init() {
        entityManagerFactory = Persistence.createEntityManagerFactory( "templatePU" );
    }

    @After
    public void destroy() {
        entityManagerFactory.close();
    }

    // Entities are auto-discovered, so just add them anywhere on class-path
    // Add your tests, using standard JUnit.
    @Test
    public void hhh123Test() throws Exception {
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        entityManager.getTransaction().begin();
        // Do stuff...
        entityManager.getTransaction().commit();
        entityManager.close();
    }
}

The EntityManagerFactory is created before every test case and destroyed afterwards. The test case logic goes inside the @Test Junit method.

You should name the test method after the Hibernate JIRA issue you are trying to replicate.

The EntityManagerFactory uses the templatePU Persistence Unit, which is located under src/test/resources/META-INF/persistence.xml. By default, this file looks like this:

<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_1.xsd"
             version="2.1">

    <persistence-unit name="templatePU" transaction-type="RESOURCE_LOCAL">

        <description>Hibernate test case template Persistence Unit</description>
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>

        <exclude-unlisted-classes>false</exclude-unlisted-classes>

        <properties>
            <property name="hibernate.archive.autodetection" value="class, hbm"/>

            <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
            <property name="hibernate.connection.driver_class" value="org.h2.Driver"/>
            <property name="hibernate.connection.url" value="jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1"/>
            <property name="hibernate.connection.username" value="sa"/>

            <property name="hibernate.connection.pool_size" value="5"/>

            <property name="hibernate.show_sql" value="false"/>
            <property name="hibernate.format_sql" value="true"/>
            <property name="hibernate.hbm2ddl.auto" value="create-drop"/>

            <property name="hibernate.max_fetch_depth" value="5"/>

            <property name="hibernate.cache.region_prefix" value="hibernate.test"/>
            <property name="hibernate.cache.region.factory_class"
                      value="org.hibernate.testing.cache.CachingRegionFactory"/>

            <!--NOTE: hibernate.jdbc.batch_versioned_data should be set to false when testing with Oracle-->
            <property name="hibernate.jdbc.batch_versioned_data" value="true"/>

            <property name="javax.persistence.validation.mode" value="NONE"/>
            <property name="hibernate.service.allow_crawling" value="false"/>
            <property name="hibernate.session.events.log" value="true"/>
        </properties>

    </persistence-unit>
</persistence>

The persistence.xml configuration file is already set up for bootstrapping Hibernate, offering a reasonable default environment. In case you want to provide a different configuration, like using JTA with a stand-alone Transaction Manager, you’ll have to change the default configuration.

All entities are auto-discovered, so you can place them anywhere on classpath. In this example, we are going to use the following entity:

@Entity
public class Event {

    @Id
    @GeneratedValue
    private Long id;

    @Temporal(TemporalType.TIMESTAMP )
    private Date createdOn;

    public Event() {
    }

    public Event(Date createdOn) {
        this.createdOn = createdOn;
    }

    public Long getId() {
        return id;
    }

    public Date getCreatedOn() {
        return createdOn;
    }
}

Now, the persistence logic can be added to the JUnit test method:

@Test
public void hhh123Test() throws Exception {
    EntityManager entityManager = entityManagerFactory.createEntityManager();
    entityManager.getTransaction().begin();

    Event event = new Event( new Date() );
    entityManager.persist( event );

    Event dbEvent = entityManager.createQuery(
            "select e " +
            "from Event e", Event.class)
        .getSingleResult();
    assertEquals(event.getCreatedOn(), dbEvent.getCreatedOn());

    entityManager.getTransaction().commit();
    entityManager.close();
}

That’s it! You can now provide a Hibernate test case using the standard Java Persistence API.

Hibernate Community Newsletter 1/2016

Posted by    |       |    Tagged as Discussions Hibernate ORM

Happy New Year, everyone!

Starting this year, we are going to host a series of articles focused on the Hibernate community. We are going to share blog posts, forum and StackOverflow questions, that are especially relevant to our users.

Articles

Thorben Janssen, who regularly writes about JPA and Hibernate topics, has summarized the most typical logging configurations in a Hibernate Logging Guide.

For our Portuguese readers, Rafael Ponte has written a very interesting article about bidirectional relationships and the caveats of not properly synchronizing both ends of a bidirectional association.

One topic, I always wanted to investigate in great details, is about the aggressive connection release behavior employed for JTA transactions. For high-performance data access platforms, it’s worth checking if the Java EE application server can operate successfully even without aggressive connection release.

Building the Hibernate blog with Docker on Windows

Posted by    |       |    Tagged as Discussions

For my first post, I’d like to share the experience of running the in.relation.to blog on my Windows machine.

All the blog content is available on GitHub, and you can practically run the whole site on your local environment.

The Hibernate blog is built with awestruct from Asciidoctor files, and getting all the Ruby gems in place is definite not a walk in the park. To make matters worse, I’m running a Windows machine and all these Ruby gems are tightly coupled to Linux libraries, as I discovered after several failed attempts with the 64 bits Ruby 2.2.4 or the 32 bits Ruby 1.9.3.

Luckily, there is a dockerfile available, so building a Docker image and run it in a dedicated container can tackle the Ruby gem hell. Building the Docker image was fine, but running it was a three hours hackathon for both Emmanuel and I.

Docker images are immutable and all changes are wiped out once the container is terminated. Instead, we want the GitHub repository to be mirrored in the Docker container, so all changes are persisted even after shutting down the docker machine. This process can be done by mounting a host folder into the Docker container, which can happen upon running the Docker image. In our case, the mounted directory is the GitHub repository that’s mirrored inside the currently running Docker container.

Once the image is built, we need to run this command from within the GitHub repository folder:

docker run -t -i -p 4242:4242 -v `pwd`:/home/dev/in.relation.to hibernate/in.relation.to

This doesn’t work on Windows because Docker needs the OS paths to be prefixed with another slash.

So this command must be changed to:

docker run -t -i -p 4242:4242 -v '/'`pwd`:/home/dev/in.relation.to hibernate/in.relation.to

After running it, the mounted folder was just empty. We noticed that without the GitHub folder mounting part the Docker image could run properly, so the mounting process was the culprit.

After all sorts of hacks, Emmanuel had the idea of checking the Virtual Box Shared Folders, and, by default, only the C:\Users directory is being shared. No wonder it was not working all along.

All my repositories being on D:\, we thought that adding a new shared path would fix this issue. Well, it didn’t.

Docker must mount these Virtual Box shared folders too, but it only does so for C:\Users. There’s a GitHub issue detailing this behavior, which you can watch if you are interested in this feature.

After moving the checkout GitHub repository to /c/Users/Vlad/GitHub/in.relation.to, it all worked fine.

back to top