Java and JDBC for Oracle DBAs – Part 6: Spring-boot, JPA and Hibernate

In the last article we looked at Spring-boot and accessed the database using the JdbcTemplate class.Today we’ll rewrite the same application but by using JPA and Hibernate instead. The Spring Initializr web page have changed a little since the last time, so the first part will be a little different.

Part 6: Spring-boot, JPA and Hibernate

Disclaimer

First of all, this is not a tutorial on JPA and Hibernate. If you are looking for such a tutorial, you can go to one of the many tutorials out there (for instance “Tutorialpoint – Hibernate” or “Vlad Mihalcea“. This blog is a part of a blog series showing different ways Java Developers work towards an Oracle database. Today we are showing the use of JPA and Hibernate.

I used to hate Hibernate. Why show you?

I have been hired into a lot of projects with performance issues caused by Hibernate. Well – for many years, I thought Hibernate was the big evil. Since then I have learned that this is not really the case. It’s the developers using Hibernate, either the wrong way or for the wrong problems. I have also seen many projects having a lot of success with Hibernate.
In DBA scenarios, such as Oracle User Group conferences, I often hear people laugh whenever Hibernate is mentioned, or people saying “you should never use Hibernate”. I think this is completely wrong, and only makes the distance between DBAs and Java developers bigger.

So in this article we’ll have our first look at this “awful” tool that very many Java developers use when writing code towards relational databases.

What is JPA?

JPA (or Java Persistence API) is just a specification, and consist of only interfaces. So it is not a product in it self, and requires an implementation. The JPA specification describes a way of accessing, persisting, and managing data between Java objects and relational databases. One of these implementations are found in Hibernate, which we’ll have a look at below.

What is Hibernate

Hibernate is an ORM API, used when writing Java code to map between Objects in the code and relations in an relational database. Hibernate provides both an proprietary POJO API and an implementation of the JPA specification. So Hibernate can be used without JPA, and JPA can be used with another implementation such as TopLink.

The todays demo application: SpringHibernateDemo

Spring Initializr

We’ll start up by using the Spring Initializr at https://start.spring.io/. Choose the following settings:

Then add the dependencies by using the search functionality. Write “web” in the “Search dependencies to add”. Below you should now see different libraries showing up. Click the plus sign on the “Web” library:

Do the same for “JDBC” and “JPA”. You should then end up with the following dependencies:

Note! You could also add “Flyway” the same way as “JDBC” and “JPA” (shown above). Instead we’ll add this manually in the pom.xml file in the next section.

Click the “Generate Project” button, and save the “spring-hibernate.zip” file. Unzip the file in a suitable location, and open project in Eclipse (File -> “Open Project from File System …”).

Adding Oracle JDBC and Flyway dependencies

Add the Oracle JDBC and Flyway dependencies to the pom.xml:

	<dependency>
            <groupId>org.flywaydb</groupId>
            <artifactId>flyway-core</artifactId>
        </dependency>

       <dependency>
            <groupId>com.oracle.jdbc</groupId>
            <artifactId>ojdbc8</artifactId>
            <version>12.2.0.1</version>
       </dependency>

And then the Flyway build dependencies and configuration:

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
			<plugin>
                <groupId>org.flywaydb</groupId>
                <artifactId>flyway-maven-plugin</artifactId>
                <configuration>
                    <url>jdbc:oracle:thin:@localhost:152/ORCL</url>
                    <user>demo</user>
                    <password>demo</password>
                    <locations>db/migration/</locations>
                    <table>SCHEMA_VERSION</table>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>com.oracle.jdbc</groupId>
                        <artifactId>ojdbc8</artifactId>
                        <version>12.2.0.1</version>
                    </dependency>
                </dependencies>
            </plugin>
		</plugins>
	</build>
Copy the Flyway DB script

We’ll use the same EMP table as in part 5. Copy the Flyway script (V1__table_emp.sql) from “src/main/resources/db/migration” (in spring-jdbc project) to a similar directory in the spring-hibernate project. After I wrote part 5 I have had some bad experience with IDENTITY columns and the auto-generated sequence. If you delete the table, you won’t be able to delete the sequence (as I know). So I’ll change this to the good-old sequence, but with a default value:

create sequence emp_seq start with 1 increment by 1 cache 100;

create table emp(
  empno    number(4,0) DEFAULT emp_seq.nextval,
  ename    varchar2(10),
  job      varchar2(9),
  mgr      number(4,0),
  hiredate date,
  sal      number(10,2),
  comm     number(7,2),
  deptno   number(2,0),
  constraint pk_emp primary key (empno)
);

insert into emp (ename, job, mgr, hiredate, sal, comm, deptno) values ('LARRY', 'CEO', null, sysdate-4000, 10000, null, 10);
insert into emp (ename, job, mgr, hiredate, sal, comm, deptno) values ('KING', 'Sales', 1000, sysdate-3000, 5000, null, 30);
commit;

Test the flyway setup by using the maven command line utility:

Lasses-MacBook-Pro-5:~ lassejenssen$ cd WS/spring-hibernate
Lasses-MacBook-Pro-5:spring-hibernate lassejenssen$ &amp;lt;strong&amp;gt;mvn flyway:clean&amp;lt;/strong&amp;gt;
[INFO] ------------------&amp;lt; no.eritec.demo:spring-hibernate &amp;gt;-------------------
[INFO] Building spring-hibernate 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- flyway-maven-plugin:5.2.4:clean (default-cli) @ spring-hibernate ---
[INFO] Flyway Community Edition 5.2.4 by Boxfuse
[INFO] Database: jdbc:oracle:thin:@localhost:152/ORCL (Oracle 12.2)
[INFO] Successfully cleaned schema "DEMO" (execution time 00:01.998s)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4.666 s
[INFO] Finished at: 2019-03-18T17:34:16+01:00
[INFO] ------------------------------------------------------------------------
Lasses-MacBook-Pro-5:spring-hibernate lassejenssen$ &amp;lt;strong&amp;gt;mvn flyway:migrate&amp;lt;/strong&amp;gt;
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------&amp;lt; no.eritec.demo:spring-hibernate &amp;gt;-------------------
[INFO] Building spring-hibernate 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- flyway-maven-plugin:5.2.4:migrate (default-cli) @ spring-hibernate ---
[INFO] Flyway Community Edition 5.2.4 by Boxfuse
[INFO] Database: jdbc:oracle:thin:@localhost:152/ORCL (Oracle 12.2)
[INFO] Successfully validated 1 migration (execution time 00:00.018s)
[INFO] Creating Schema History table: "DEMO"."SCHEMA_VERSION"
[INFO] Current version of schema "DEMO": &amp;lt;&amp;lt; Empty Schema &amp;gt;&amp;gt;
[INFO] Migrating schema "DEMO" to version 1 - table emp
[INFO] Successfully applied 1 migration to schema "DEMO" (execution time 00:00.205s)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.373 s
[INFO] Finished at: 2019-03-18T17:34:29+01:00
[INFO] ------------------------------------------------------------------------
Lasses-MacBook-Pro-5:spring-hibernate lassejenssen$

Adding Entity class: Employee

Now you should be comfortable at creating a new package. Create the “no.eritec.demo.springhibernate.entity” package, and copy the Employee.java file from your project from part 5 (from the domain package). Change the import of “java.sql.Date” to “java.util.Date”:

package no.eritec.demo.springhibernate.entity;

import java.util.Date;

public class Employee {
	
	private int empno;
	private String ename;
	private String job;
	private int managerNo;
	private Date hiredate;
	private int salary;
	private int comm;
	private int deptno;
	
	public Employee() {
		super();
	}
	
	public Employee(
			int empno, 
			String ename,
			String job,
			int managerNo,
			int salary,
			int comm,
			int deptno) {
		this.empno = empno;
		this.ename = ename;
		this.job = job;
		this.managerNo = managerNo;
		this.salary = salary;
		this.comm = comm;
		this.deptno = deptno;
	}

	public Date getHiredate() {
		return hiredate;
	}

	public void setHiredate(Date hiredate) {
		this.hiredate = hiredate;
	}
	
	public int getEmpno() {
		return empno;
	}

	public void setEmpno(int empno) {
		this.empno = empno;
	}

	public String getEname() {
		return ename;
	}

	public void setEname(String ename) {
		this.ename = ename;
	}

	public String getJob() {
		return job;
	}

	public void setJob(String job) {
		this.job = job;
	}

	public int getManagerNo() {
		return managerNo;
	}

	public void setManagerNo(int managerNo) {
		this.managerNo = managerNo;
	}

	public int getSalary() {
		return salary;
	}

	public void setSalary(int salary) {
		this.salary = salary;
	}

	public int getComm() {
		return comm;
	}

	public void setComm(int comm) {
		this.comm = comm;
	}

	public int getDeptno() {
		return deptno;
	}

	public void setDeptno(int deptno) {
		this.deptno = deptno;
	}

}
JPA annotations

Now we’ll start adding JPA annotations. First we tell Spring that this class is an @Entity. We also map the Employee class to the EMP table in the database by using the @Table annotation:

import javax.persistence.Entity;
import javax.persistence.Table;

@Entity
@Table(name="EMP")
public class Employee { ...

Then we add the @Id annotation for the primary key column, and use the @GeneratedValue to tell Spring that this value will be generated automatically by Oracle (because of the default value and sequence). We also use the @Column annotation to map columns with a different name in the entity class (than in the database). At last I change the datatypes for those columns which are nullable away from primitive datatypes.

The complete Employee class:

package no.eritec.demo.springhibernate.entity;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="EMP")
public class Employee {
	
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO, generator = "EMP_SEQ")
	private int empno;
	private String ename;
	private String job;
	@Column(name="mgr")
	private Integer managerNo;
	private Date hiredate;
	@Column(name="sal")
	private Double salary;
	private Integer comm;
	private Integer deptno;
	
	public Employee() {
		super();
	}
	
	public Employee(
			int empno, 
			String ename,
			String job,
			int managerNo,
			int salary,
			int comm,
			int deptno) {
		this.empno = empno;
		this.ename = ename;
		this.job = job;
		this.managerNo = managerNo;
		this.salary = salary;
		this.comm = comm;
		this.deptno = deptno;
	}

	public Date getHiredate() {
		return hiredate;
	}

	public void setHiredate(Date hiredate) {
		this.hiredate = hiredate;
	}
	
	public int getEmpno() {
		return empno;
	}

	public void setEmpno(int empno) {
		this.empno = empno;
	}

	public String getEname() {
		return ename;
	}

	public void setEname(String ename) {
		this.ename = ename;
	}

	public String getJob() {
		return job;
	}

	public void setJob(String job) {
		this.job = job;
	}

	public int getManagerNo() {
		return managerNo;
	}

	public void setManagerNo(int managerNo) {
		this.managerNo = managerNo;
	}

	public int getSalary() {
		return salary;
	}

	public void setSalary(int salary) {
		this.salary = salary;
	}

	public int getComm() {
		return comm;
	}

	public void setComm(int comm) {
		this.comm = comm;
	}

	public int getDeptno() {
		return deptno;
	}

	public void setDeptno(int deptno) {
		this.deptno = deptno;
	}

}

 

Creating a database repository class

Now we’ll be writing the code accessing the EMP table in the database. Or actually, we’ll let Spring create it for us. The only thing we need to do is to create a repository interface extending the JpaRepository class.

Start by adding a new package: “no.eritec.demo.springhibernate.repository”.

In the new package create a new interface: “EmployeeRepository”:

package no.eritec.demo.springhibernate.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import no.eritec.demo.springhibernate.entity.Employee;

@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Integer> {
}

Adding the Spring database connection information

Now we just need to configure the application to which database and schema to connect to when running. We also add configuration which tell the JPA implementation to show the SQLs ran in the log. We add all this in the application.properties file:

spring.datasource.driver-class-name=oracle.jdbc.OracleDriver
spring.datasource.url=jdbc:oracle:thin:@//localhost:1521/orcl
spring.datasource.username=demo
spring.datasource.password=demo

# Show all queries
spring.jpa.show-sql=true

Writing the test class (SpringHibernateApplicationTest)

Then we are ready to write some test code in the test class SpringHibernateApplicationTest (found under “/src/test/java”). I start by adding a Logger variable, so I can write to the log output.

I create three test methods: One for adding a new Employee (test1AddEmployee), one for listing all the employees (test2ShowEmployees), and one counting the employees (test3CountEmployees). I start every method by “testN” (where N is an increasing integer) and add the annotation @FixMethodOrder(MethodSorters.NAME_ASCENDING) to the class. Now the test methods will run in the order they are listed:

package no.eritec.demo.springhibernate;

import java.util.Date;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import no.eritec.demo.JavaOugnDemo.JavaOugnDemoApplicationTests;
import no.eritec.demo.springhibernate.entity.Employee;
import no.eritec.demo.springhibernate.repository.EmployeeRepository;

@RunWith(SpringRunner.class)
@SpringBootTest
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class SpringHibernateApplicationTests {
	Logger log = LoggerFactory.getLogger(SpringHibernateApplicationTests.class);
	
	@Autowired
	EmployeeRepository repo;

	@Test
	public void contextLoads() {
	}
	
	@Test
	public void test1AddEmployee() {
		Employee emp = new Employee();
		emp.setEname("HARRY");
		emp.setDeptno(10);
		emp.setHiredate(new Date());
		emp.setJob("Sales");
		Employee emp2 = repo.save(emp);
		assertNotNull(emp2.getEmpno());
	}
	
	@Test
	public void test2ShowEmployees() {
		log.info("Employees:");
		log.info("=========================");
		List list = repo.findAll();
		for (Employee e:list) {
			log.info(e.getEname());
		}
		assertEquals(list.size(),4);
	}
	
	@Test
	public void test3CountEmployees() {
		int cnt = (int) repo.count();
		log.info("Count: " + cnt);
		assertEquals(cnt,4);
	}

}

Now you can click the “Run” button to run your tests. Note! You might need to do a “mvn flyway:clean” first. You could also run this using maven from command line:

Lasses-MacBook-Pro-5:spring-hibernate lassejenssen$ mvn flyway:clean
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------< no.eritec.demo:spring-hibernate >-------------------
[INFO] Building spring-hibernate 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[WARNING] The POM for javax.xml.bind:jaxb-api:jar:2.3.1 is invalid, transitive dependencies (if any) will not be available, enable debug logging for more details
[INFO]
[INFO] --- flyway-maven-plugin:5.2.4:clean (default-cli) @ spring-hibernate ---
[INFO] Flyway Community Edition 5.2.4 by Boxfuse
[INFO] Database: jdbc:oracle:thin:@localhost:152/ORCL (Oracle 12.2)
[INFO] Successfully cleaned schema "DEMO" (execution time 00:00.255s)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.105 s
[INFO] Finished at: 2019-03-18T20:11:39+01:00
[INFO] ------------------------------------------------------------------------


Lasses-MacBook-Pro-5:spring-hibernate lassejenssen$ mvn package
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------< no.eritec.demo:spring-hibernate >-------------------
[INFO] Building spring-hibernate 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[WARNING] The POM for javax.xml.bind:jaxb-api:jar:2.3.1 is invalid, transitive dependencies (if any) will not be available, enable debug logging for more details
[INFO]
[INFO] --- maven-resources-plugin:3.1.0:resources (default-resources) @ spring-hibernate ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource
[INFO] Copying 2 resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.0:compile (default-compile) @ spring-hibernate ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-resources-plugin:3.1.0:testResources (default-testResources) @ spring-hibernate ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /Users/lassejenssen/WS/spring-hibernate/src/test/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.0:testCompile (default-testCompile) @ spring-hibernate ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-surefire-plugin:2.22.1:test (default-test) @ spring-hibernate ---
[INFO]
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running no.eritec.demo.springhibernate.SpringHibernateApplicationTests
20:12:04.218 [main] DEBUG org.springframework.test.context.junit4.SpringJUnit4ClassRunner - SpringJUnit4ClassRunner constructor called with [class no.eritec.demo.springhibernate.SpringHibernateApplicationTests]
20:12:04.224 [main] DEBUG org.springframework.test.context.BootstrapUtils - Instantiating CacheAwareContextLoaderDelegate from class [org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate]
20:12:04.230 [main] DEBUG org.springframework.test.context.BootstrapUtils - Instantiating BootstrapContext using constructor [public org.springframework.test.context.support.DefaultBootstrapContext(java.lang.Class,org.springframework.test.context.CacheAwareContextLoaderDelegate)]
20:12:04.250 [main] DEBUG org.springframework.test.context.BootstrapUtils - Instantiating TestContextBootstrapper for test class [no.eritec.demo.springhibernate.SpringHibernateApplicationTests] from class [org.springframework.boot.test.context.SpringBootTestContextBootstrapper]
20:12:04.262 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Neither @ContextConfiguration nor @ContextHierarchy found for test class [no.eritec.demo.springhibernate.SpringHibernateApplicationTests], using SpringBootContextLoader
20:12:04.265 [main] DEBUG org.springframework.test.context.support.AbstractContextLoader - Did not detect default resource location for test class [no.eritec.demo.springhibernate.SpringHibernateApplicationTests]: class path resource [no/eritec/demo/springhibernate/SpringHibernateApplicationTests-context.xml] does not exist
20:12:04.265 [main] DEBUG org.springframework.test.context.support.AbstractContextLoader - Did not detect default resource location for test class [no.eritec.demo.springhibernate.SpringHibernateApplicationTests]: class path resource [no/eritec/demo/springhibernate/SpringHibernateApplicationTestsContext.groovy] does not exist
20:12:04.265 [main] INFO org.springframework.test.context.support.AbstractContextLoader - Could not detect default resource locations for test class [no.eritec.demo.springhibernate.SpringHibernateApplicationTests]: no resource found for suffixes {-context.xml, Context.groovy}.
20:12:04.266 [main] INFO org.springframework.test.context.support.AnnotationConfigContextLoaderUtils - Could not detect default configuration classes for test class [no.eritec.demo.springhibernate.SpringHibernateApplicationTests]: SpringHibernateApplicationTests does not declare any static, non-private, non-final, nested classes annotated with @Configuration.
20:12:04.309 [main] DEBUG org.springframework.test.context.support.ActiveProfilesUtils - Could not find an 'annotation declaring class' for annotation type [org.springframework.test.context.ActiveProfiles] and class [no.eritec.demo.springhibernate.SpringHibernateApplicationTests]
20:12:04.395 [main] DEBUG org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider - Identified candidate component class: file [/Users/lassejenssen/WS/spring-hibernate/target/classes/no/eritec/demo/springhibernate/SpringHibernateApplication.class]
20:12:04.397 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Found @SpringBootConfiguration no.eritec.demo.springhibernate.SpringHibernateApplication for test class no.eritec.demo.springhibernate.SpringHibernateApplicationTests
20:12:04.486 [main] DEBUG org.springframework.boot.test.context.SpringBootTestContextBootstrapper - @TestExecutionListeners is not present for class [no.eritec.demo.springhibernate.SpringHibernateApplicationTests]: using defaults.
20:12:04.487 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener, org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener, org.springframework.boot.test.autoconfigure.restdocs.RestDocsTestExecutionListener, org.springframework.boot.test.autoconfigure.web.client.MockRestServiceServerResetTestExecutionListener, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcPrintOnlyOnFailureTestExecutionListener, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverTestExecutionListener, org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener]
20:12:04.495 [main] DEBUG org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Skipping candidate TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener] due to a missing dependency. Specify custom listener classes or make the default listener classes and their required dependencies available. Offending class: [javax/servlet/ServletContext]
20:12:04.502 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Using TestExecutionListeners: [org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@384ad17b, org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener@61862a7f, org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener@441772e, org.springframework.test.context.support.DirtiesContextTestExecutionListener@7334aada, org.springframework.test.context.transaction.TransactionalTestExecutionListener@1d9b7cce, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener@4d9e68d0, org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener@42e99e4a, org.springframework.boot.test.autoconfigure.restdocs.RestDocsTestExecutionListener@14dd9eb7, org.springframework.boot.test.autoconfigure.web.client.MockRestServiceServerResetTestExecutionListener@52e6fdee, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcPrintOnlyOnFailureTestExecutionListener@6c80d78a, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverTestExecutionListener@62150f9e]
20:12:04.504 [main] DEBUG org.springframework.test.annotation.ProfileValueUtils - Retrieved @ProfileValueSourceConfiguration [null] for test class [no.eritec.demo.springhibernate.SpringHibernateApplicationTests]
20:12:04.504 [main] DEBUG org.springframework.test.annotation.ProfileValueUtils - Retrieved ProfileValueSource type [class org.springframework.test.annotation.SystemProfileValueSource] for class [no.eritec.demo.springhibernate.SpringHibernateApplicationTests]
20:12:04.506 [main] DEBUG org.springframework.test.annotation.ProfileValueUtils - Retrieved @ProfileValueSourceConfiguration [null] for test class [no.eritec.demo.springhibernate.SpringHibernateApplicationTests]
20:12:04.506 [main] DEBUG org.springframework.test.annotation.ProfileValueUtils - Retrieved ProfileValueSource type [class org.springframework.test.annotation.SystemProfileValueSource] for class [no.eritec.demo.springhibernate.SpringHibernateApplicationTests]
20:12:04.507 [main] DEBUG org.springframework.test.annotation.ProfileValueUtils - Retrieved @ProfileValueSourceConfiguration [null] for test class [no.eritec.demo.springhibernate.SpringHibernateApplicationTests]
20:12:04.507 [main] DEBUG org.springframework.test.annotation.ProfileValueUtils - Retrieved ProfileValueSource type [class org.springframework.test.annotation.SystemProfileValueSource] for class [no.eritec.demo.springhibernate.SpringHibernateApplicationTests]
20:12:04.512 [main] DEBUG org.springframework.test.context.support.AbstractDirtiesContextTestExecutionListener - Before test class: context [DefaultTestContext@7b9a4292 testClass = SpringHibernateApplicationTests, testInstance = [null], testMethod = [null], testException = [null], mergedContextConfiguration = [MergedContextConfiguration@4a94ee4 testClass = SpringHibernateApplicationTests, locations = '{}', classes = '{class no.eritec.demo.springhibernate.SpringHibernateApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@30a3107a, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@52feb982, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@36b4cef0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@45820e51], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map[[empty]]], class annotated with @DirtiesContext [false] with mode [null].
20:12:04.513 [main] DEBUG org.springframework.test.annotation.ProfileValueUtils - Retrieved @ProfileValueSourceConfiguration [null] for test class [no.eritec.demo.springhibernate.SpringHibernateApplicationTests]
20:12:04.513 [main] DEBUG org.springframework.test.annotation.ProfileValueUtils - Retrieved ProfileValueSource type [class org.springframework.test.annotation.SystemProfileValueSource] for class [no.eritec.demo.springhibernate.SpringHibernateApplicationTests]
20:12:04.518 [main] DEBUG org.springframework.test.context.support.DependencyInjectionTestExecutionListener - Performing dependency injection for test context [[DefaultTestContext@7b9a4292 testClass = SpringHibernateApplicationTests, testInstance = no.eritec.demo.springhibernate.SpringHibernateApplicationTests@5158b42f, testMethod = [null], testException = [null], mergedContextConfiguration = [MergedContextConfiguration@4a94ee4 testClass = SpringHibernateApplicationTests, locations = '{}', classes = '{class no.eritec.demo.springhibernate.SpringHibernateApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@30a3107a, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@52feb982, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@36b4cef0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@45820e51], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map[[empty]]]].
20:12:04.541 [main] DEBUG org.springframework.test.context.support.TestPropertySourceUtils - Adding inlined properties to environment: {spring.jmx.enabled=false, org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true, server.port=-1}

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.3.RELEASE)

2019-03-18 20:12:04.731  INFO 34704 --- [           main] n.e.d.s.SpringHibernateApplicationTests  : Starting SpringHibernateApplicationTests on Lasses-MacBook-Pro-5.local with PID 34704 (started by lassejenssen in /Users/lassejenssen/WS/spring-hibernate)
2019-03-18 20:12:04.732  INFO 34704 --- [           main] n.e.d.s.SpringHibernateApplicationTests  : No active profile set, falling back to default profiles: default
2019-03-18 20:12:05.038  INFO 34704 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data repositories in DEFAULT mode.
2019-03-18 20:12:05.093  INFO 34704 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 49ms. Found 1 repository interfaces.
2019-03-18 20:12:05.616  INFO 34704 --- [           main] o.f.c.internal.license.VersionPrinter    : Flyway Community Edition 5.2.4 by Boxfuse
2019-03-18 20:12:05.625  INFO 34704 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2019-03-18 20:12:06.160  INFO 34704 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2019-03-18 20:12:06.163  INFO 34704 --- [           main] o.f.c.internal.database.DatabaseFactory  : Database: jdbc:oracle:thin:@//localhost:152/orcl (Oracle 12.2)
2019-03-18 20:12:06.394  INFO 34704 --- [           main] o.f.core.internal.command.DbValidate     : Successfully validated 2 migrations (execution time 00:00.019s)
2019-03-18 20:12:06.495  INFO 34704 --- [           main] o.f.c.i.s.JdbcTableSchemaHistory         : Creating Schema History table: "DEMO"."flyway_schema_history"
2019-03-18 20:12:06.661  INFO 34704 --- [           main] o.f.core.internal.command.DbMigrate      : Current version of schema "DEMO": << Empty Schema >>
2019-03-18 20:12:06.662  INFO 34704 --- [           main] o.f.core.internal.command.DbMigrate      : Migrating schema "DEMO" to version 1 - table emp
2019-03-18 20:12:06.808  INFO 34704 --- [           main] o.f.core.internal.command.DbMigrate      : Migrating schema "DEMO" to version 2 - table dept
2019-03-18 20:12:06.855  INFO 34704 --- [           main] o.f.core.internal.command.DbMigrate      : Successfully applied 2 migrations to schema "DEMO" (execution time 00:00.362s)
2019-03-18 20:12:07.058  INFO 34704 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [
	name: default
	...]
2019-03-18 20:12:07.218  INFO 34704 --- [           main] org.hibernate.Version                    : HHH000412: Hibernate Core {5.3.7.Final}
2019-03-18 20:12:07.220  INFO 34704 --- [           main] org.hibernate.cfg.Environment            : HHH000206: hibernate.properties not found
2019-03-18 20:12:07.344  INFO 34704 --- [           main] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.0.4.Final}
2019-03-18 20:12:07.471  INFO 34704 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.Oracle12cDialect
2019-03-18 20:12:07.538  INFO 34704 --- [           main] org.hibernate.type.BasicTypeRegistry     : HHH000270: Type registration [byte[]] overrides previous : org.hibernate.type.BinaryType@34585ac9
2019-03-18 20:12:07.538  INFO 34704 --- [           main] org.hibernate.type.BasicTypeRegistry     : HHH000270: Type registration [[B] overrides previous : org.hibernate.type.BinaryType@34585ac9
2019-03-18 20:12:07.539  INFO 34704 --- [           main] org.hibernate.type.BasicTypeRegistry     : HHH000270: Type registration [Byte[]] overrides previous : org.hibernate.type.WrapperBinaryType@167381c7
2019-03-18 20:12:07.539  INFO 34704 --- [           main] org.hibernate.type.BasicTypeRegistry     : HHH000270: Type registration [[Ljava.lang.Byte;] overrides previous : org.hibernate.type.WrapperBinaryType@167381c7
2019-03-18 20:12:07.988  INFO 34704 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2019-03-18 20:12:08.445  INFO 34704 --- [           main] n.e.d.s.SpringHibernateApplicationTests  : Started SpringHibernateApplicationTests in 3.902 seconds (JVM running for 4.58)
Hibernate: select emp_seq.nextval from dual
Hibernate: insert into emp (comm, deptno, ename, hiredate, job, mgr, sal, empno) values (?, ?, ?, ?, ?, ?, ?, ?)
2019-03-18 20:12:08.594  INFO 34704 --- [           main] n.e.d.s.SpringHibernateApplicationTests  : Employees:
2019-03-18 20:12:08.594  INFO 34704 --- [           main] n.e.d.s.SpringHibernateApplicationTests  : =========================
2019-03-18 20:12:08.635  INFO 34704 --- [           main] o.h.h.i.QueryTranslatorFactoryInitiator  : HHH000397: Using ASTQueryTranslatorFactory
Hibernate: select employee0_.empno as empno1_0_, employee0_.comm as comm2_0_, employee0_.deptno as deptno3_0_, employee0_.ename as ename4_0_, employee0_.hiredate as hiredate5_0_, employee0_.job as job6_0_, employee0_.mgr as mgr7_0_, employee0_.sal as sal8_0_ from emp employee0_
2019-03-18 20:12:08.759  INFO 34704 --- [           main] n.e.d.s.SpringHibernateApplicationTests  : LARRY
2019-03-18 20:12:08.759  INFO 34704 --- [           main] n.e.d.s.SpringHibernateApplicationTests  : KING
2019-03-18 20:12:08.759  INFO 34704 --- [           main] n.e.d.s.SpringHibernateApplicationTests  : LINDA
2019-03-18 20:12:08.759  INFO 34704 --- [           main] n.e.d.s.SpringHibernateApplicationTests  : HARRY
Hibernate: select count(*) as col_0_0_ from emp employee0_
2019-03-18 20:12:08.780  INFO 34704 --- [           main] n.e.d.s.SpringHibernateApplicationTests  : Count: 4
[INFO] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 4.688 s - in no.eritec.demo.springhibernate.SpringHibernateApplicationTests
2019-03-18 20:12:08.819  INFO 34704 --- [       Thread-4] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2019-03-18 20:12:08.822  INFO 34704 --- [       Thread-4] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2019-03-18 20:12:08.882  INFO 34704 --- [       Thread-4] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO]
[INFO] --- maven-jar-plugin:3.1.1:jar (default-jar) @ spring-hibernate ---
[INFO] Building jar: /Users/lassejenssen/WS/spring-hibernate/target/spring-hibernate-0.0.1-SNAPSHOT.jar
[INFO]
[INFO] --- spring-boot-maven-plugin:2.1.3.RELEASE:repackage (repackage) @ spring-hibernate ---
[INFO] Replacing main artifact with repackaged archive
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 7.883 s
[INFO] Finished at: 2019-03-18T20:12:10+01:00
[INFO] ------------------------------------------------------------------------

Customizing the EmployeeRepository

In addition to all the methods inherited from the JpaRepository class, I would also like to have a method that let me search by name. Then I extend my EmployeeRepository interface, and add another test method to my test class.

New version of EmployeeRepository.java:

@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Integer>{
	 @Query("SELECT e FROM Employee e  WHERE e.ename like :eName")
	 List findByName(@Param("eName") String ename);
}

New test method:

	@Test
	public void test4SearchByName() {
		List list = repo.findByName("L%");
		int cnt = list.size();
		log.info("Count employees starting with 'L': " + cnt);
		assertEquals(cnt,2);
	}

And then you can run the “mvn flyway:clean” and “mvn package” again.

Running Flyway clean from code

If you don’t want to run “mvn flyway:clean” before running your test, you can run this from your test class.
Under I have added code to make Flyway do a “clean” and a “migrate” in the contextLoads method:

@RunWith(SpringRunner.class)
@SpringBootTest
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class SpringHibernateApplicationTests {
	Logger log = LoggerFactory.getLogger(SpringHibernateApplicationTests.class);
	
	@Autowired
	EmployeeRepository repo;
	
	@Autowired
	DataSource dataSource;
	
	@Test
	public void contextLoads() {
	    final Flyway flyway = new Flyway();
	    flyway.setDataSource(dataSource);

	    log.info("FLYWAY: Starting clean");
	    flyway.clean();
	    log.info("FLYWAY: Starting migration");
	    flyway.migrate();
	    log.info("FLYWAY: Migration Complete");
	}
        
        ...
}

This gives the following output when running the test:

2019-03-19 10:32:02.651  INFO 43287 --- [           main] n.e.d.s.SpringHibernateApplicationTests  : FLYWAY: Starting clean
2019-03-19 10:32:02.653  INFO 43287 --- [           main] o.f.c.internal.database.DatabaseFactory  : Database: jdbc:oracle:thin:@//localhost:152/orcl (Oracle 12.2)
2019-03-19 10:32:03.606  INFO 43287 --- [           main] o.f.core.internal.command.DbClean        : Successfully cleaned schema "DEMO" (execution time 00:00.928s)
2019-03-19 10:32:03.608  INFO 43287 --- [           main] n.e.d.s.SpringHibernateApplicationTests  : FLYWAY: Starting migration
2019-03-19 10:32:03.631  INFO 43287 --- [           main] o.f.core.internal.command.DbValidate     : Successfully validated 2 migrations (execution time 00:00.006s)
2019-03-19 10:32:03.713  INFO 43287 --- [           main] o.f.c.i.s.JdbcTableSchemaHistory         : Creating Schema History table: "DEMO"."flyway_schema_history"
2019-03-19 10:32:03.871  INFO 43287 --- [           main] o.f.core.internal.command.DbMigrate      : Current version of schema "DEMO": << Empty Schema >>
2019-03-19 10:32:03.872  INFO 43287 --- [           main] o.f.core.internal.command.DbMigrate      : Migrating schema "DEMO" to version 1 - table emp
2019-03-19 10:32:04.003  INFO 43287 --- [           main] o.f.core.internal.command.DbMigrate      : Migrating schema "DEMO" to version 2 - table dept
2019-03-19 10:32:04.045  INFO 43287 --- [           main] o.f.core.internal.command.DbMigrate      : Successfully applied 2 migrations to schema "DEMO" (execution time 00:00.335s)
2019-03-19 10:32:04.050  INFO 43287 --- [           main] n.e.d.s.SpringHibernateApplicationTests  : FLYWAY: Migration Complete

Post a Comment

Your email is never published nor shared. Required fields are marked *