Moving forward with toy Standalone JPA Project..

.. which utilizes a few more things including H2DB in auto server mode, Named Query example and an EntityListener!

This Example Includes..

  • Using H2DB in Auto_Server mode.
  • Using Hibernate with the c3po connection pool. 
  • Creating a sample database in every run with Hibernate property: hbm2ddl.auto and import.sql in the classpath.
  • Setting the default root logger level to WARN..
  • Example usage of maven-compiler-plugin.
  • Solving the UTF-8 when running unit tests with the maven-surefire-plugin.
  • Integration tests for a toy DAO class with a database in a known state.
  • NamedQuery example.
  • EntityListener example.
  • OneToOne relation with CascadeType.ALL.

Directory Layout

pom.xml
<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/maven-v4_0_0.xsd">
 
    <modelVersion>4.0.0</modelVersion>
 
    <groupId>biz.tugay</groupId>
    <artifactId>jpa-examples</artifactId>
    <packaging>jar</packaging>
 
    <version>1.0-SNAPSHOT</version>
 
    <name>jpa-examples</name>
    <url>http://www.tugay.biz</url>
 
    <dependencies>
        <dependency>
            <groupId>org.eclipse.persistence</groupId>
            <artifactId>javax.persistence</artifactId>
            <version>2.1.1</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>5.2.10.Final</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.5.2</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-c3p0</artifactId>
            <version>5.2.10.Final</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.4.192</version>
            <scope>runtime</scope>
        </dependency>
 
        <!-- Test Tools -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-all</artifactId>
            <version>1.10.19</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
 
    <build>
        <finalName>jpa-examples</finalName>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.2.1</version>
                <configuration>
                    <mainClass>biz.tugay.jpaExamples.App</mainClass>
                    <commandlineArgs>-Dfile.encoding=UTF-8</commandlineArgs>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.6.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.20</version>
                <configuration>
                    <enableAssertions>true</enableAssertions>
                    <argLine>-Dfile.encoding=UTF-8</argLine>
                </configuration>
            </plugin>
        </plugins>
    </build>
 
    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
</project>

persistence.xml
<?xml version="1.0" encoding="UTF-8" ?>
<persistence 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"
             version="2.0">
    <persistence-unit name="jpaExamples" transaction-type="RESOURCE_LOCAL">
        <class>biz.tugay.jpaExamples.model.Employee</class>
        <class>biz.tugay.jpaExamples.model.EmployeeLedger</class>
        <properties>
            <property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
            <property name="javax.persistence.jdbc.url"
                      value="jdbc:h2:~/sampleh2db;TRACE_LEVEL_FILE=0;AUTO_SERVER=TRUE"/>
            <property name="javax.persistence.jdbc.user" value="test"/>
            <property name="javax.persistence.jdbc.password" value="test"/>
        </properties>
    </persistence-unit>
</persistence>

hibernate.properties
# suppress inspection "UnusedProperty" for whole file
hibernate.c3p0.min_size=1
hibernate.c3p0.max_size=10
hibernate.c3p0.timeout=300
hibernate.c3p0.max_statements=5
hibernate.c3p0.unreturnedConnectionTimeout=2
 
hibernate.hbm2ddl.auto=create
hibernate.show_sql=false

import.sql
-- noinspection SqlResolve
SET FOREIGN_KEY_CHECKS =0;
 
INSERT INTO PUBLIC.EMPLOYEE (ID, FIRSTNAME, LASTNAME, ADDRESS, CITY, EMPLOYEE_LEDGER_ID) VALUES (-1, 'Furkan', 'Survivor', 'Yıldız Caddesi', 'İstanbul', -1);
INSERT INTO PUBLIC.EMPLOYEE (ID, FIRSTNAME, LASTNAME, ADDRESS, CITY, EMPLOYEE_LEDGER_ID) VALUES (-2, 'Update_Me', 'Update_Me', '', '', -2);
INSERT INTO PUBLIC.EMPLOYEE (ID, FIRSTNAME, LASTNAME, ADDRESS, CITY, EMPLOYEE_LEDGER_ID) VALUES (-3, 'Delete_Me', 'Delete_Me', '', '', NULL);
 
INSERT INTO PUBLIC.EMPLOYEE_LEDGER (ID, MONTHLY_SALARY) VALUES (-1, 6500.25);
INSERT INTO PUBLIC.EMPLOYEE_LEDGER (ID, MONTHLY_SALARY) VALUES (-2, 1000);
 
-- noinspection SqlResolve
SET FOREIGN_KEY_CHECKS=1;

Employee.java
package biz.tugay.jpaExamples.model;
 
import javax.persistence.*;
 
@Entity
@NamedQuery(name = "all", query = "SELECT e FROM Employee e")
@EntityListeners(EmployeePersistenceListener.class)
public class Employee {
 
    private long id;
    private String firstname;
    private String lastname;
    private String address;
    private String city;
    private EmployeeLedger employeeLedger;
 
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public long getId() {
        return id;
    }
 
    public void setId(long id) {
        this.id = id;
    }
 
    public String getFirstname() {
        return firstname;
    }
 
    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }
 
    public String getLastname() {
        return lastname;
    }
 
    public void setLastname(String lastname) {
        this.lastname = lastname;
    }
 
    public String getAddress() {
        return address;
    }
 
    public void setAddress(String address) {
        this.address = address;
    }
 
    public String getCity() {
        return city;
    }
 
    public void setCity(String city) {
        this.city = city;
    }
 
    @OneToOne(targetEntity = EmployeeLedger.class, fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinColumn(name = "EMPLOYEE_LEDGER_ID")
    public EmployeeLedger getEmployeeLedger() {
        return employeeLedger;
    }
 
    public void setEmployeeLedger(EmployeeLedger employeeLedger) {
        this.employeeLedger = employeeLedger;
    }
 
    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", firstname='" + firstname + '\'' +
                ", lastname='" + lastname + '\'' +
                ", address='" + address + '\'' +
                ", city='" + city + '\'' +
                ", employeeLedger=" + employeeLedger +
                '}';
    }
}

EmployeeLedger.java
package biz.tugay.jpaExamples.model;
 
import javax.persistence.*;
 
@Entity
@Table(name = "EMPLOYEE_LEDGER")
public class EmployeeLedger {
 
    private long id;
    private double monthlySalary;
 
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public long getId() {
        return id;
    }
 
    public void setId(long id) {
        this.id = id;
    }
 
    @Column(name = "MONTHLY_SALARY")
    public double getMonthlySalary() {
        return monthlySalary;
    }
 
    public void setMonthlySalary(double monthlySalary) {
        this.monthlySalary = monthlySalary;
    }
 
    @Override
    public String toString() {
        return "EmployeeLedger{" +
                "id=" + id +
                ", monthlySalary=" + monthlySalary +
                '}';
    }
}

EmployeePersistenceListener.java
package biz.tugay.jpaExamples.model;
 
import javax.persistence.PreRemove;
 
public class EmployeePersistenceListener {
 
    @PreRemove
    public void logDeletion(final Object o) {
        final Employee employee = (Employee) o;
        System.out.println("Employee: " + employee + " deleted.");
    }
}

EmployeeBuilder.java
package biz.tugay.jpaExamples.model.builder;
 
import biz.tugay.jpaExamples.model.Employee;
 
public final class EmployeeBuilder {
 
    private final Employee employee = new Employee();
 
    public EmployeeBuilder firstname(final String firstname) {
        employee.setFirstname(firstname);
        return this;
    }
 
    public EmployeeBuilder lastname(final String lastname) {
        employee.setLastname(lastname);
        return this;
    }
 
    public Employee build() {
        return employee;
    }
}

EmployeeLedgerBuilder.java
package biz.tugay.jpaExamples.model.builder;
 
import biz.tugay.jpaExamples.model.EmployeeLedger;
 
public final class EmployeeLedgerBuilder {
 
    final EmployeeLedger employeeLedger = new EmployeeLedger();
 
    public EmployeeLedgerBuilder monthlySalary(final double monthlySalary) {
        employeeLedger.setMonthlySalary(monthlySalary);
        return this;
    }
 
    public EmployeeLedger build() {
        return employeeLedger;
    }
}

EmployeeDaoImpl.java
package biz.tugay.jpaExamples.dao;
 
import biz.tugay.jpaExamples.model.Employee;
import biz.tugay.jpaExamples.service.EntityManagerService;
 
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.TypedQuery;
import java.util.List;
 
public final class EmployeeDaoImpl {
 
    private EntityManagerService entityManagerService;
 
    public void insert(final Employee employee) {
        final EntityManager entityManager = entityManagerService.entityManager();
        entityManager.persist(employee);
        entityManager.getTransaction().begin();
        entityManager.getTransaction().commit();
        entityManager.close();
    }
 
    public Employee byId(final long id) {
        final EntityManager entityManager = entityManagerService.entityManager();
        final Employee employee = entityManager.find(Employee.class, id);
        entityManager.close();
        return employee;
    }
 
    public List<Employee> all() {
        final EntityManager entityManager = entityManagerService.entityManager();
        final TypedQuery<Employee> queryAll = entityManager.createNamedQuery("all", Employee.class);
        final List<Employee> allEmployees = queryAll.getResultList();
        entityManager.close();
        return allEmployees;
    }
 
    public void update(final Employee employee) {
        final EntityManager entityManager = entityManagerService.entityManager();
        entityManager.merge(employee);
        final EntityTransaction transaction = entityManager.getTransaction();
        transaction.begin();
        transaction.commit();
        entityManager.close();
    }
 
    public void delete(final Employee employee) {
        final EntityManager entityManager = entityManagerService.entityManager();
        final Employee employeeToBeRemoved = entityManager.getReference(Employee.class, employee.getId());
        entityManager.remove(employeeToBeRemoved);
 
        final EntityTransaction transaction = entityManager.getTransaction();
        transaction.begin();
        transaction.commit();
 
        entityManager.close();
    }
 
    public void setEntityManagerService(final EntityManagerService entityManagerService) {
        this.entityManagerService = entityManagerService;
    }
}

EntityManagerService.java
package biz.tugay.jpaExamples.service;
 
import javax.persistence.EntityManager;
 
public interface EntityManagerService {
    EntityManager entityManager();
    void closeEntityManagerFactory();
}

EntityManagerServiceByPersistenceUnitNameImpl.java
package biz.tugay.jpaExamples.service;
 
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
 
public final class EntityManagerServiceByPersistenceUnitNameImpl implements EntityManagerService {
 
    private static EntityManagerFactory entityManagerFactory;
 
    private EntityManagerServiceByPersistenceUnitNameImpl() {
        // Use the static method serviceForPersistenceUnitName to get an instance of this class!
    }
 
    public static EntityManagerService serviceForPersistenceUnitName(final String persistenceUnitName) {
        if (entityManagerFactory == null || entityManagerFactory.isOpen()) {
            entityManagerFactory = Persistence.createEntityManagerFactory(persistenceUnitName);
        }
        return new EntityManagerServiceByPersistenceUnitNameImpl();
    }
 
    @Override
    public EntityManager entityManager() {
        final EntityManager entityManager = entityManagerFactory.createEntityManager();
        return entityManager;
    }
 
    @Override
    public void closeEntityManagerFactory() {
        entityManagerFactory.close();
    }
}

BaseTest.java
package biz.tugay.jpaExamples;
 
import java.util.logging.Level;
import java.util.logging.Logger;
 
public class BaseTest {
    static {
        final Logger globalLogger = Logger.getLogger("");
        globalLogger.setLevel(Level.WARNING);
    }
}

BaseDaoTest.java
package biz.tugay.jpaExamples.dao;
 
import biz.tugay.jpaExamples.BaseTest;
import biz.tugay.jpaExamples.service.EntityManagerService;
import biz.tugay.jpaExamples.service.EntityManagerServiceByPersistenceUnitNameImpl;
import org.junit.AfterClass;
 
public class BaseDaoTest extends BaseTest {
    private final static String PERSISTENCE_UNIT_NAME = "jpaExamples";
    protected final static EntityManagerService entityManagerService = EntityManagerServiceByPersistenceUnitNameImpl.serviceForPersistenceUnitName(PERSISTENCE_UNIT_NAME);
 
    @AfterClass
    public static void closeFactory() {
        entityManagerService.closeEntityManagerFactory();
    }
}

EmployeeDaoImplTest.java
package biz.tugay.jpaExamples.dao;
 
import biz.tugay.jpaExamples.model.Employee;
import biz.tugay.jpaExamples.model.EmployeeLedger;
import biz.tugay.jpaExamples.model.builder.EmployeeBuilder;
import biz.tugay.jpaExamples.model.builder.EmployeeLedgerBuilder;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;
 
import java.util.List;
 
@RunWith(MockitoJUnitRunner.class)
public class EmployeeDaoImplTest extends BaseDaoTest {
 
    final EmployeeDaoImpl employeeDao = new EmployeeDaoImpl();
 
    {
        employeeDao.setEntityManagerService(entityManagerService);
    }
 
    @Test
    public void testInsert() {
        // Given..
        final Employee employee = new EmployeeBuilder().firstname("Yıldız").lastname("Yıldız").build();
        final EmployeeLedger employeeLedger = new EmployeeLedgerBuilder().monthlySalary(1000D).build();
        employee.setEmployeeLedger(employeeLedger);
 
        Assert.assertTrue(employee.getId() == 0L);
 
        // When
        employeeDao.insert(employee);
 
        // Then
        Assert.assertTrue(employee.getId() != 0);
        Assert.assertTrue(employee.getFirstname().equals("Yıldız"));
        Assert.assertTrue(employeeLedger.getId() != 0);
    }
 
    @Test
    public void testByID() {
        // Given..
        // Sample data contains Employee with id -1L..
 
        // When..
        final Employee employee = employeeDao.byId(-1L);
        final EmployeeLedger employeeLedger = employee.getEmployeeLedger();
 
        // Then..
        Assert.assertTrue(employee.getFirstname().equals("Furkan"));
        Assert.assertTrue(employeeLedger.getMonthlySalary() == 6500.25);
    }
 
    @Test
    public void testAll() {
        // Given..
        // Sample data should containt at least one Employee..
 
        // When..
        final List<Employee> all = employeeDao.all();
 
        // Then..
        Assert.assertTrue(all.size() > 0);
    }
 
    @Test
    public void testUpdate() {
        // Given..
        final Employee employee = employeeDao.byId(-2L);
        Assert.assertTrue(employee.getEmployeeLedger().getMonthlySalary() == 1000);
 
        // When..
        final EmployeeLedger employeeLedger = employee.getEmployeeLedger();
        employeeLedger.setMonthlySalary(employeeLedger.getMonthlySalary() * 2);
        employeeDao.update(employee);
 
        // Then..
        Assert.assertTrue(employee.getEmployeeLedger().getMonthlySalary() == 2000);
    }
 
    @Test
    public void testDelete() {
        // Given..
        final Employee employee = employeeDao.byId(-3L);
        Assert.assertTrue(employee.getFirstname().equals("Delete_Me"));
 
        // When..
        employeeDao.delete(employee);
 
        // Then..
        Assert.assertTrue(employeeDao.byId(-3L) == null);
    }
}