Skip to main content

Java EE Application Development – Creating a JPA Module and Organizing Project Structure

JPA is an ORM used to map Java objects to the database. It is similar to Hibernate, but it uses EntityManger instead of Session to manage objects and it can utilize context dependency injection, a spring counterpart provided in Java EE, I will talk about this in later posts. Before we start adding the JPA module, let’s talk about organizing maven modules first.

Organizing Projects

Maven is a powerful dependency management tool. You can build your project with its strong flexibility in configuring how your projects should be structured. You can group your project into a single root project, for pom.xml inheritance and projects building. Our project structure is updated to use a root maven module to manage all sub-modules’ lifecycle.

First, let’s create a new maven module from IntelliJ, giving the groupId com.zxuqian, artifactId notebookRoot, version 0.0.1-SNAPSHOT. This will be our root project of all other maven modules. You can run maven clean or install goals simply on this project, and manage dependencies too. The pom.xml file content is

<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.zxuqian</groupId>
  <artifactId>notebookRoot</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>pom</packaging>

  <dependencyManagement>
    <dependencies>
      <dependency>
          <groupId>org.wildfly.bom</groupId>
          <artifactId>wildfly-javaee7</artifactId>
          <scope>import</scope>
          <type>pom</type>
          <version>10.1.0.Final</version>
        </dependency>
    </dependencies>
  </dependencyManagement>
  
  <dependencies>

  </dependencies>
  <modules>
    <module>../notebook</module>
    <module>../notebookDomain</module>
    <module>../notebookEAR</module>
  </modules>
</project>

The <packaging> means this project actually is not a project, just a pom file that other modules can inherit.

The <dependencyManagement> uses wildfly bom with import scope to manage versions of wildfly libraries so that you don’t have to define <version> tag in your sub-module pom files.

The <modules> tag references other modules so that running maven goals will run on each module as well. The notebookDomain and notebookEAR are the modules we will create next.

Update the JSF module

As we changed our project structure, the JSF module pom.xml need a few changes. The new pom.xml is:

<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.zxuqian</groupId>
  <artifactId>notebook</artifactId>
  <packaging>war</packaging>

  <parent>
    <groupId>com.zxuqian</groupId>
    <artifactId>notebookRoot</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <relativePath>../notebookRoot/pom.xml</relativePath>
  </parent>
  
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.5.1</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>
      <plugin>
        <artifactId>maven-war-plugin</artifactId>
        <version>3.0.0</version>
        <configuration>
          <warSourceDirectory>WebContent</warSourceDirectory>
        </configuration>
      </plugin>
    </plugins>
  </build>
  <dependencies>
    <dependency>
      <groupId>org.jboss.spec.javax.faces</groupId>
      <artifactId>jboss-jsf-api_2.2_spec</artifactId>
      <scope>provided</scope>
    </dependency>
  </dependencies>
</project>

Notice the <parent> tag, it reference to the notebookRoot module. The JSF dependencies now become to org.jboss.spec.javax.faces.jboss-jsf-api_2.2_spec as we are using wildfly bom, it is the default implementation of JSF.

Install MySQL database

To install MySQL database, reference the documentation in MySQL official website: https://dev.mysql.com/doc/refman/5.7/en/osx-installation-pkg.html

Here I’m using MySQL 5.7.

Create a JDBC resource

First, you should download mysql jdbc connector from here: https://dev.mysql.com/downloads/connector/j/

Unzip it get the mysql-connector-java-5.1.40-bin.jar.

Before you start wildfly server, you should add a user to login the console.  Execute

/Users/zxuqian/development/tools/wildfly-10.1.0.Final/bin/add-user.sh

Follow the instructions to create a Management User.

Now start wildfly server in the terminal:

/Users/zxuqian/development/tools/wildfly-10.1.0.Final/bin/standalone.sh

Login in to the console: http://localhost:9990

On the welcome page, click start near the deploy an Application in Deployment parts. We will first deploy the mysql jdbc connector to the server. Click Add on the following page:

Choose upload a new deployment, click next.

Select the connector jar file that you unzipped, click next.

Keep the names and click finish.

Now back to home page, click start near create a datasource in configuration part. On the following page, select Subsystems -> Datasources -> Non-XA. Click Add on the right up corner of datasource.

Choose MySQL datasource. Click next.

Give it a name and a JNDI name, the JNDI name is very important, it will be used in the persistent.xml configuration file of our JPA module. Click next.

Click detected driver and select the first one. Click next.

Define the connection URL. Here I use notebook database, you should create this before you define the URL. Using “create database notebook” statement against your database. Specify the username and password used to connect to your database. Click next.

Review summary. If all correct, click finish.

You can test the connection by this:

If successful, the following prompt will be shown:

Create a JPA module

Create a new module from intelliJ, with the following groupId, artifactId, and select parent com.zxuqian:notebookRoot:0.0.1-SNAPSHOT, which we created in previous steps:

The content of the pom.xml file is:

<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.zxuqian</groupId>
  <artifactId>notebookDomain</artifactId>
  <packaging>jar</packaging>
  
  <parent>
    <groupId>com.zxuqian</groupId>
    <artifactId>notebookRoot</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <relativePath>../notebookRoot/pom.xml</relativePath>
  </parent>
  
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.5.1</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>
    </plugins>
  </build>

  <dependencies>

    <dependency>
      <groupId>org.hibernate.javax.persistence</groupId>
      <artifactId>hibernate-jpa-2.1-api</artifactId>
      <scope>provided</scope>
    </dependency>

  </dependencies>
</project>

<packaging> indicates this module will be packaged as a jar file that can be deployed as a Java EE module.

 

maven-compiler-plugin is configured to use jdk 1.8 to compile your code.

As wildfly provides hibernate JAP implementation, so you declare that dependency with scope provided, which only provided during compiling phase.

Create an Entity

An entity is the java object that relating to a table in the relational database. We will use JPA annotations to config how entities map to tables. Let’s create a Java class called User and write some code:

package com.zxuqian.notebook.domain;

import java.io.Serializable;
import java.util.Date;

import javax.persistence.*;

/**
 * Entity implementation class for Entity: User
 *
 */
@Entity
public class User implements Serializable {

    private static final long serialVersionUID = 1L;
    
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private long id;
    private String username;
    private String password;
    private Date dateOfBirth;
    private String email;
    private String phone;

    public User() {
        super();
    }

    public long getId() {
        return id;
    }

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Date getDateOfBirth() {
        return dateOfBirth;
    }

    public void setDateOfBirth(Date dateOfBirth) {
        this.dateOfBirth = dateOfBirth;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }
    
   
}

It’s a simple plain old java bean (POJO). It needs to implement a Serializable interface for JPA to serialize to and deserialize from the database. The @Entity annotation makes it a JPA Entity, and using the class name as the table name. @Id annotation means the id field is the primary key. @GeneratedValue(strategy=GenerationType.IDENTITY) will let the database automatically generate a unique value for the id column. The rest fields without annotations will have the column name as the same as variable names.

In the src/META-INF directory, create a file named persistence.xml with the following content:

<?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="notebookDomain">
        <jta-data-source>java:/MySqlDS</jta-data-source>
        <properties>
            <property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>
            <property name="javax.persistence.schema-generation.scripts.action" value="none"/>
        </properties>
    </persistence-unit>
</persistence>

This is the configuration file for JPA modules. The <jta-data-source> is the JNDI name that you defined in the wildfly. The drop-and-create value of javax.persistence.schema-generation.database.action property means tables are dropped and created everytime you deploy the application. The javax.persistence.schema-generation.scripts.action property means whether you would like JPA to generate the SQL DDL for you.

Create an EAR module

As we have JSF module and JPA module separately, so we have to package them to an ear package. This is the enterprise application package that can be recognized as a group of sub-modules by the application server. The pom.xml file is shown below:

<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.zxuqian</groupId>
  <artifactId>notebookEAR</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>ear</packaging>
  
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-ear-plugin</artifactId>
        <version>2.10</version>
        <configuration>
          <earSourceDirectory>EarContent</earSourceDirectory>
          <version>7</version>
          <defaultLibBundleDir>lib</defaultLibBundleDir>
          <modules>
            <webModule>
              <groupId>com.zxuqian</groupId>
              <artifactId>notebook</artifactId>
              <contextRoot>/notebook</contextRoot>
            </webModule>
          </modules>
        </configuration>
      </plugin>

        <plugin>
            <groupId>org.wildfly.plugins</groupId>
            <artifactId>wildfly-maven-plugin</artifactId>
            <version>1.2.0.Alpha2</version>
            <configuration>
                <jbossHome>/Users/zxuqian/development/tools/wildfly-10.1.0.Final</jbossHome>
            </configuration>
        </plugin>

    </plugins>
  </build>
  
  <dependencies>
    <dependency>
      <groupId>com.zxuqian</groupId>
      <artifactId>notebook</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <type>war</type>
    </dependency>
    <dependency>
      <groupId>com.zxuqian</groupId>
      <artifactId>notebookDomain</artifactId>
      <version>0.0.1-SNAPSHOT</version>
    </dependency>
  </dependencies>
</project>

The <webModule> defines which module is web module, this is our JSF module, and define the context root as /notebook. Here I use the wildfly-plugin so that we can deploy our application easily by executing the wildfly maven goals. You should define your wildfly home directory, or it will download a new wildfly application server for you. The dependencies are the modules that will be included in the ear package.

Run the application

In IntelliJ, click View – Tool Windows – Maven Projects from the menu, the following window will appear:

To build the project, double click the install lifecycle under the notebookRoot module. To deploy it to wildfly, double click wildfly:run under plugins in notebookEAR module. To verify if the database table is successfully created not, connection to MySQL database, and do the following query:

use notebook;

describe user;

If you can see the result from describing the user table, then it is successful.