[JPA Practical Part] Deploy and Explore Working JPA Application

This article is the practical part of the JPA introductory materials I and II. We are going to explore a mock library application that utilizes various JPA features.

The library application is available in the github repository as the JPA_I project.

Prerequisites

Ensure you have followed steps in the JPA Setup guide. That means at this point, you have:

  • A running database server
  • A running Wildfly server with deployed datasource that is bound to the following JNDI: java:/jboss/BookDB

Admin walkthrough

Our application is connected to the server mainly via the persistence.xml. A couple of highlights:

  • The jta-data-source tag utilizes the JNDI name, which exposes our database. At this point, we are using database set on the application server without the need to pass the username, password, and other sensitive information into our application.
  • The SQL tables are dropped (if they exist), (re-)created, and loaded with content each deployment of the application. You can find the SQL scripts here. If you manage to drop your tables, simply redeploy your application and all data will be back.
  • Some of the settings, such as hibernate.show_sql, make it easy to see the SQL statements generated by Hibernate based on our code. After you try the application, check the Wildfly logs to see the actual SQL that Hibernate generated.

I also included the datasource.xml file. This file is not necessary for our application, but shows you exactly what has been done on server side when you added the datasource into Wildfly configuration. The contents of the datasource.xml file is present in your standalone.xml. You can find it in ${WILDFLY_HOME}/standalone/configuration/standalone.xml.

Deployment

To deploy the application:

  1. Download it from the github repository. If you have git installed, issue git clone https://github.com/m-czernek/halfastack.com.git Otherwise, download and unzip it manually.
  2. Change into the project directory:
    1. On Unix, issue:cd halfastack.com/JPA_1/.
    2. On Windows, issue: cd halfastack.com/JPA_1/.
  3. Build the project with Maven: mvn clean package.
  4. Copy the war archive into the deployments directory of your Wildfly server. In the following steps, SERVER_HOME is the directory where is your Wildfly server:
    1. On Unix, issue: cp target/JPA_I.war SERVER_HOME/standalone/deployments
    2. On Windows, issue: copy target\JPA_I.war SERVER_HOME\standalone\deployments

If successful, you should see something similar in the console log of Wildfly:

Note that you can also see executing the SQL scripts:

This is useful to keep in mind when further working with the code.

You can now access the application at http://localhost:8080/JPA_I/ :

Library app accessible on localhost:8080

Troubleshooting

The deployment may fail due to a number of reasons:

  1. The database server is not running, or is blocked by a firewall (common on Windows)
  2. The database server does not have  a database named bookDb (check the command with which you started HSQLDB server)
  3. The application server (Wildfly) does not expose the correct JNDI. In that case, you can either correct the JNDI in the application server’s settings, or in your persistence.xml settings.

Exploring the source code

JPA Mapping

With every JPA application, one of the most important classes are the entity classes. You can find our entities in the package com.halfastack.entities:

  • Author
  • Book

Probably the most crucial is JPA mapping. Each Author object has a number of books, but each Book object has only one author. Therefore, you can see the following mapping:

When mapping classes, I personally like to think that the direction of mapping goes from top of the class down (top-to-bottom). In this class, that means:

  • Book (class level, is higher than fields) ->Author (field level, is lower than class definition)
  • Many Book objects -> one Author object.

As such, we use the ManyToOne annotation. Furthermore, we see that in the SQL table, the Library table which maps to our Book entity has a foreign key AUTHOR, which references the ID of the Author table. Because of that, we the JoinColumn annotation on the AUTHOR table field.

The Author class then has the following mapping:

If we stick to our top-to-bottom analogy, then it means:

  • Author -> Book
  • One Author object  -> many Book objects

As such, we use the OneToMany annotation. Note that the mappedBy field of the annotation refers to the Book Java class, not to the underlying SQL table. In the SQL table, the Author table has no connection to any other table. In JPA, one class always maps to the SQL table while the other maps to another Java class.

Because an author has many books in our case, it makes sense for the field to be a List of books. Note that we did not account for a book having multiple authors.

I also used a different table name for the Book entity, which maps to the Library table, and a different field name for the Author entity (surname maps to the SECONDNAME SQL field). This is just to show you how easy it is to map entities even when they are not matching exactly with their SQL table.

Custom SQL Statements

Notice that our BookDB class has become a true database manager. No longer does it have a dummy HashMap of Author-Book strings; it now operates with the underlying database. As such, we had to write our own SQL statements:

Here, you can see how to:

  1. Use the EntityManager class to create TypedQuery objects
  2. Set parameters on your queries
  3. Execute the queries

For parameters, I used the number notation rather than the named-parameter notation (see the theoretical articles for more detail on the topic).

The rest of the project, such as the frontend controller, has undergone only slight changes from the EJB_I project. As such, if you’re curious about the code and cannot understand it, see the EJB Code Walkthrough.

Learn by doing

To truly learn the subject matter, you should enhance the application’s functionality. Feature requests:

  • Modify the application such that you can add books.
  • At this point, if you enter empty string, you get all the titles in the database. This is due to:
    • No value entered into a text field is interpreted as an empty String
    • The nature of our SQL statements
      Make it such that empty String is interpreted as NULL value.
  • Add another entity into our application: a Customer entity which has the following fields:
    • First name
    • Surname
    • Address
    • List of Book entities that he or she has lent

Make it such that you can search for who has lent which books. Do not forget to alter the SQL tables and enter new values into your new field. Expand on the provided SQL files.

Summary

You now understand basics of JPA. Answer the following questions:

  1. Describe what is relational mapping.
  2. Describe what is a JPA entity.
  3. Describe how do you create queries in JPA.
  4. Describe how do you persist an object into the database.

In case you’re having difficulties with any of the questions, feel free to ask in the comment section, or re-visit the theoretical parts. If you’ve enjoyed this article, consider subscribing to our email list, so that you can be informed when new article is posted.

Leave a Reply