Integration testing using Testcontainers in a Spring Boot 2, JPA application

In this post we will be looking at how to perform integration testing of the repository layer using Testcontainer. We will be setting up Testcontainer in a Spring Boot 2 application, use JPA for persistence and PostgreSQL as database.Besides this we will also be using JUnit5 framework.

Why Integration testing of the database ?

In any software application, it is a known fact that data is of utmost importance. In a web application, this data will usually be handled at the database layer. In an application which uses JPA for persistence, the repository and the JPA entities are major components of the database layer.

To ensure that the repository layer and the entities are functioning appropriately, we should write unit tests. Unit tests for the same are usually written against an in memory database. This is definitely required. The only catch here – Should we wait until production to ensure that the database layer is behaving as expected against our actual type of our database as against the in memory database ?

What would be even better is if we can do integration testing against a similar database that we use in production environment – MySQL,Oracle,PostgreSQL etc. But wouldn’t setting this up be difficult and laborious for just integration testing ?

Enter Testcontainers

Using Testcontainers, we can actually start a containerized instance of the database to test our database layer without going through the pain of actually setting it up on every developer’s machine. Testcontainer is a Java library that provides disposable and lightweight instances of databases. It actually does a lot more that just that. You can read about it here.

How does it help us ?

Using JUnit tests against the actual type of our production database will give us feedback before we actually go into production.This means we can worry less about our database layer and breathe a little easy. There will always be other issues in production,NullPointerExceptions in our code that we can worry about! Since Testcontainers spawns a containerized environment for us to run our tests, we need to have Docker installed.

Getting started with the code

We will be using Spring Boot 2.3.0 along with Spring Data JPA, JUnit 5 to run the tests,Flyway to create tables and TestContainer version 1.14.1.

Snippet of the pom.xml
<!-- The PostgreSQL db driver -->        
<dependency>
	<groupId>org.postgresql</groupId>
	<artifactId>postgresql</artifactId>
	<scope>test</scope>
</dependency> 
<dependency>
	<groupId>org.testcontainers</groupId>
	<artifactId>testcontainers</artifactId>
	<version>${testcontainer.version}</version>
	<scope>test</scope>	
</dependency>
<!-- test container support for postgre module -->
<dependency>
        <groupId>org.testcontainers</groupId>
        <artifactId>postgresql</artifactId>
        <version>${testcontainer.version}</version>
        <scope>test</scope>
</dependency>
<!-- JUnit 5 integration with testcontainer -->
<dependency>
	<groupId>org.testcontainers</groupId>
	<artifactId>junit-jupiter</artifactId>
	<version>${testcontainer.version}</version>
	<scope>test</scope>
</dependency>
The application.properties file
spring.jpa.hibernate.ddl-auto=none
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQL94Dialect
spring.jpa.show-sql=true

The spring.jpa.hibernate.ddl-auto has been set to none because we are using flyway to create our database and tables. The initialization script can be found under the /db/migration folder.

Starting the containerized PostgreSQL database and tying it with Spring
public abstract class AbstractContainerBaseTest {

	protected static final PostgreSQLContainer postgres;

	static {
		postgres = new PostgreSQLContainer("postgres:9.6.15")
										 .withDatabaseName("socialmediasite")
										 .withUsername("postgres")
										 .withPassword("password");
		//Mapped port can only be obtained after container is started.
		postgres.start();
	}
	
	static class PropertiesInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
		public void initialize(ConfigurableApplicationContext configurableApplicationContext) {			
			TestPropertyValues
					.of("spring.datasource.driver-class-name=" + postgres.getDriverClassName(),
							"spring.datasource.url=" + postgres.getJdbcUrl(),
							"spring.datasource.username=" + postgres.getUsername(),
							"spring.datasource.password=" + postgres.getPassword())
					.applyTo(configurableApplicationContext.getEnvironment());
		}
	}
}

The main purpose of this abstract class is to start the container using Testcontainer library. All other test classes will extend this class .The static block creates the container and this instance will be shared by all test classes. There is a manual call to start method. The library manages to shut it down automatically.

The PropertiesInitializer class is needed because we need to access this containerized database through the Spring Data JPA.

Initialization of Testcontainer,PostgreSQL, Spring Boot,Spring Data JPA
Verifying the output
PostgreSQL container created and closed by Testcontainer

I am using the docker ps –format command to list the containers started by Testcontainer library. As shown in the image above, one can see the container having the name competent_raman which is the PostgreSQL container.For all the test cases this is the single instance of the container. There is also this additional image quay.io/testcontainers/ryuk:0.2.3 – this is created by the Testcontainer library which ensures all other containers are shut down and cleaned when the JVM shuts down.

Database and tables in the containerized PostgreSQL database.

As you can see in the image above, I am using the docker exec -it command to connect to the same containerized instance, (competent_raman) of the PostgreSQL database. Then using the command psql -h 192.168.99.100 -p 32813, we are connected to the dockerized database. The -p indicates the port number and -h the host. The \c socialmediasite command connects us to the database and finally the \d command is used to list all the tables.

Once all the tests are executed, the Testcontainer library removes the instances of the containers that it created.

The JPA entities SocialMediaSite and User used in the application have a One-Many relationship.

Conclusion

Writing unit tests against an in-memory database like H2 is certainly helpful but writing integration tests against actual type of production database takes us to the next level – more confidence, fewer failures in production. The combination of Testcontainers, Spring Boot 2, JUnit5 makes it easy for us to get started on this journey. You can find the entire source code here.

Understanding @SpringBootApplication

The objective of this post is to get an understanding of what @SpringBootApplication annotation does in a Spring Boot application. Sometimes we just tend to add an annotation, everything works magically and we are happy.

But when we want to make a few changes, things start breaking, components are not found and then we blame the magic that we enjoyed earlier.So it is always a good idea to get a better understanding of what some of these annotations do.

In a Spring Boot application, we need a class with a main method annotated with @SpringBootApplication annotation as shown below:

package com.boot.jpa;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootJpaApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringBootJpaApplication.class, args);
	}

}

This is the starting point for a Spring Boot application. The @SpringBootApplication annotation is really a short hand annotation or a combination of the following annotations:

1. @SpringBootConfiguration

This signifies that the application is not just a normal Spring application but a Spring Boot application. Actually this is just a combination of @Configuration+ Spring Boot, so more of a specialization. @Configuration applied on a file signifies that the class contains spring bean configurations using @Bean.

2. @EnableAutoConfiguration

This is the super intelligent annotation which kicks in the auto configuration for Spring Boot. Auto configuration is done by inspecting the classpath and configuring necessary beans that may be required. If you were to provide your own configuration, then Spring Boot will not re-configure the bean again.

How is this auto configuration done ?

Auto Configuration is done via a SpringFactoriesLoader class which will pick up and read the META-INF/spring.factories file.  It is like a hook into instantiating certain beans found on the classpath. A sample of the same is shown below. EnableAutoConfiguration class is the ‘key’ below and it can have many ‘values’ as classes. These are read and conditionally configured depending on what is already configured by the developer and what is found on the classpath. For example, only if RabbitMQ and Spring AMQP client are found on the classpath usually added via maven or gradle, then Spring Boot tries to configure RabbitMQ.

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
....

3. @ComponentScan

Any Spring application will usually consist of beans which will be managed by Spring framework. To tell Spring framework to manage a bean, we use @ComponentScan. This annotation will scan all your beans and register it with the Spring Application Context. Later, you could inject the beans using @Autowired. Examples of a Component are classes annotated with @Controller, @Repository, @Service etc.

One has to be careful as @ComponentScan will scan the packages below the package from where this is defined.

A better way to organize your packages would be to have the  class containing the @SpringBootApplication in the root package of your application so that all sub packages get scanned and beans are registered with application context. If this is not possible for some reason, you can of course add @ComponentScan annotation and specify the base package(s) to scan for spring beans.

Conclusion

Annotations in the Spring or Spring Boot framework makes the life of a developer easy and increases productivity.However it is important to understand the ‘what and how’ of these annotations to be a more effective and efficient developer.

Getting Intimate with Spring Boot and Hibernate

In my previous blog , we looked at how to get started with a simple Spring Boot and Hibernate application. We managed to get our application up and running in a few minutes.

In this article, we will look at how and what Spring Boot does behind the scenes.

Basic requirement

To setup a Spring based application with Hibernate/JPA we usually need the following:

  1. Datasource  which connects to a database and details like the database url, password, username – this is really independent of whether we use Spring, JPA.
  2. JPA EntityManager to perform repository(CRUD) related operations.
  3. Vendor specific (Hibernate) properties
  4. Transaction support.

Let us take a look at how these things get configured.

In case of an in memory H2 database, all of the above was configured automatically by Spring Boot. We did not write a single configuration either using Java configuration or XML. Well, how does Spring Boot do everything for us?  Let’s take a look :

Vanishing (configuration) act explained :

1. The starting point is the spring.factories file. This file has a Auto Configure section which Spring Boot uses to determine what should be auto configured. This file is in the META-INF folder which is part of the spring-boot-autoconfigure-<version>.RELEASE.jar. The SpringFactoriesLoader class loads the spring.factories file.

2. Since we are talking about JPA/Hibernate, the spring.factories contains a (among other autoconfigurations) key value pair: org.springframework.boot.autoconfigure.EnableAutoConfiguration=\org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration

3. The key EnableAutoConfiguration above is triggered using the @SpringBootApplication annotation on the SpringBootJpaApplication.java file. This is our starting point in our application.


package com.boot.jpa;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBootJpaApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootJpaApplication.class, args);
}
}

4. The value part above, HibernatJpaAutoConfiguration class which is part of the Spring framework looks like


@Configuration
@ConditionalOnClass({ LocalContainerEntityManagerFactoryBean.class, EntityManager.class })
@Conditional(HibernateEntityManagerCondition.class)
@AutoConfigureAfter({ DataSourceAutoConfiguration.class })
public class HibernateJpaAutoConfiguration extends JpaBaseConfiguration {
….
}

One of the important annotations above is on line 4 :

@AutoConfigureAfter({ DataSourceAutoConfiguration.class }).

This indicates that we should perform HibernateJpaAutoConfiguration only after reading the DataSourceAutoConfiguration.class or only if a Datasource is found on the classpath. It would make no sense to configure JPA and Hibernate without a datasource/database !

5. The DataSourceAutoConfiguration looks as follows:


@Configuration
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class })
public class DataSourceAutoConfiguration {
}

6. This is a normal Spring Configuration class which sets up the DataSource only if all of the above annotations satisfy our criteria. We used an H2 database and hence the DataSource.class and EmbeddedDatabaseType.class satisfies the condition.

7. Now the configuration moves back to step 4 where we needed the presence of  datasource/database at minimum. Now on to the next part where the following is checked :

@ConditionalOnClass({ LocalContainerEntityManagerFactoryBean.class, EntityManager.class })

This is configuration specific to JPA classes and the @ConditionalOnClass checks if these classes are there on the class path. There are present in our case through the Spring Data JPA library.

8.Next comes the @Conditional(HibernateEntityManagerCondition.class) . This checks if the JPA provider is Hibernate, this is done via the HibernateEntityManagerCondition.java. In our case it is true since Spring Boot brings in Hibernate as the default provider of JPA and HibernateEntityManager.java is on the classpath.

9.Once these conditions are satisfied, the HibernateJpaAutoConfiguration extends the JpaBaseConfiguration class.


@EnableConfigurationProperties(JpaProperties.class)
@Import(DataSourceInitializedPublisher.Registrar.class)
public abstract class JpaBaseConfiguration implements BeanFactoryAware {
}

This is annotated with the @EnableConfigurationProperties(JpaProperties.class).  This JpaProperties.class is annotated with @ConfigurationProperties(prefix = “spring.jpa”) . This gets triggered if we were to add any spring.jpa.xxx properties in our application.properties file. We would use this if we were to add any jpa specific properties. We did not add any and hence the default is assumed.

10.The JpaBaseConfiguration class contains all the other remaining configurations. It primarily uses the @ConditionalOnMissingBean annotation to configure the EntityManager, JpaVendorAdapter, LocalContainerEntityManagerFactoryBean, JpaTransactionManager if they have already not been configured. The @ConditionalOnMissingBean when applied on a method means – if this bean has not been configured, then execute the method and configure it.


@Bean
@ConditionalOnMissingBean(PlatformTransactionManager.class)
public PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
return transactionManager;
}

So in this way, datasource, entitymanager, vendor(hibernate) specific properties and transactions get configured. If you have setup a Spring Hibernate application before, we would do the same using Java configuration or an xml and configure the above mentioned properties. You can configure any specific properties and in that case Spring Boot will skip auto configuring that property.

Conclusion 

All the Harry Houdini illusions or Spring Boot magic starts from the spring.factories file and then through the usage of some powerful annotations like @ConditionalOnMissingBean, ConditionalOnClass,@AutoConfigureAfter , Jpa/Datasource/Transactions gets configured depending on what is found in the classpath. Spring Boot will not configure a property or a bean if it was already configured.

Complaining is a Habit ?

I have heard people complaining about the so-called magic in Spring Boot. Well, when Spring folks gave us xml configurations, we complained ! They gave us configurations via annotations and Java Configuration to get rid of the xml, we still complained ! Now, things get configured automatically…..and we still complain. Complaining can be good at times, the folks at Pivotal have been listening to our complaints and have been giving us fantastic tools/ frameworks. But let’s not forget that the details are out there, let’s explore a little more before complaining.

 

 

 

 

 

Spring Boot and Hibernate – Quick Introduction

It has been a while since I wrote this blog about how I  discovered Spring Boot. A surgery to fix my ACL and meniscus tear has kept me away from a lot of things, more about that in a different blog. But it is time we got a little intimate with Spring Boot.

In this blog we will look at how to setup a simple Spring Boot application with JPA/Hibernate. I remember shying away from writing/experimenting any code whenever I heard – setting up something with Spring. Those were the dark ages ! Well, if you haven’t tried the super cool Spring Initializr yet , it is high time you did. You can setup Spring based projects in an absolute flash !

All I did was enter JPA, H2 in the Search for dependencies  box and imported the project in my IDE.

spring-boot-jpa-intializr

Dependencies

The pom.xml from the imported project contains the following important dependencies:


<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

We added 2 things in the search box, JPA and H2 and so now the pom.xml contains dependencies corresponding to that:

  1. The spring-boot-started-data-jpa dependency brings in the latest version of the Hibernate, support for transactions, spring-data-jpa etc. Not only does it bring in the latest versions but also compatible versions. Notice that we need not add spring-orm and all the pain to setup the latest and compatible versions of Hibernate, JPA, transactions. This is done automatically for us.
  2. The h2 dependency above is for an embedded database that we will be using. One can easily replace that with the respective database in your project. Since h2 database will be present on the classpath, Spring Boot will configure the h2 database for us. If you add the dependency for Mysql database, Spring Boot will help configuring a MySql database.

JPA Entity

To keep things simple, we are going to create a Project entity which contains id, name and description and persist this  data. We will use Spring Data to persist and fetch the data.

Application starting point

The starting point in our application is the SpringBootJpaApplication.java:


package com.boot.jpa;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBootJpaApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootJpaApplication.class, args);
}
}

The output from running the file above: (lines 4 – 8)


2017-06-06 00:56:10.523 INFO 616 — [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2017-06-06 00:56:10.812 INFO 616 — [ main] o.h.h.i.QueryTranslatorFactoryInitiator : HHH000397: Using ASTQueryTranslatorFactory
2017-06-06 00:56:11.204 INFO 616 — [ main] com.boot.jpa.ProjectInitRunner : Project[ id = 1 , name = 'Java' , description = 'Java based project for a bank']
2017-06-06 00:56:11.205 INFO 616 — [ main] com.boot.jpa.ProjectInitRunner : Project[ id = 2 , name = 'Scala' , description = 'Scala based project for an oil company']
2017-06-06 00:56:11.206 INFO 616 — [ main] com.boot.jpa.ProjectInitRunner : Project[ id = 3 , name = 'Apache Kafka' , description = 'Kafka based project for a data mining company']
2017-06-06 00:56:11.206 INFO 616 — [ main] com.boot.jpa.ProjectInitRunner : Getting project by name
2017-06-06 00:56:11.268 INFO 616 — [ main] com.boot.jpa.ProjectInitRunner : Scala based project id 2

Sample Data added via the Initializer

In addition to the SpringBootJpaApplication.java, there is a ProjectInitRunner.java which is run by Spring Boot on startup. It contains initialization code which inserts some Project entities into the H2 database and then fetches one of the project details. This class is run on start up as it implements the CommandLineRunner interface. I am currently using it to persist some data into the H2 database.


package com.boot.jpa;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ProjectInitRunner implements CommandLineRunner {
private static final Logger logger = LoggerFactory.getLogger(ProjectInitRunner.class);
@Autowired
private ProjectRepository projectRepository;
@Override
public void run(Stringargs) throws Exception {
// Save
projectRepository.save(new Project("Java", "Java based project for a bank"));
projectRepository.save(new Project("Scala", "Scala based project for an oil company"));
projectRepository.save(new Project("Apache Kafka", "Kafka based project for a data mining company"));
// Find all projects.
List<Project> projects = projectRepository.findAll();
projects.forEach(project -> logger.info(project.toString()));
// Get a project by name
logger.info("Getting project by name");
Project project = projectRepository.findByName("Scala");
logger.info("Scala based project id " + project.getId());
}
}

The Spring Boot starter data jpa brings in the Spring Data project which we are using to persist and retrieve the data.

Package structure

This is how the package structure looks :

spring-boot-sts-package

 

Gotchas – Packages and Spring  component scanning

Since all the classes were in the same package, the @SpringBootApplication annotation simply scanned and picked up all classes which were in the same package. This works as the @SpringBootApplication does Auto Configuration for us via the @EnableAutoConfiguration annotation. This would also work if other Spring beans were in sub or child packages.

If the Repository and the entities were in a different package with respect to the SpringBootJpaApplication.java which contains the main method, we need to do slightly more work:

spring-boot-sts-split-package

As shown above, Project.java and ProjectRepository.java are in a completely different package as compared to the class containing the main method. We need to now inform Spring Boot to enable/scan the repository and entity related classes. This is simply done by modifying the SpringBootJpaApplication.java and adding 2 annotations, @EnableJpaRepositories and @EntityScan. The annotations contain the information about packages that need to be scanned to enable the Jpa repository and scan the JPA entity related classes.No other change is needed and everything runs as usual.


package com.boot.jpa;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@SpringBootApplication
@EnableJpaRepositories(basePackages="com.boot.repository")
@EntityScan(basePackages = "com.boot.repository")
public class SpringBootJpaApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootJpaApplication.class, args);
}
}

Conclusion

So it is really quite simple and super quick to setup a Spring Boot JPA project. The starter projects brings in all the required dependencies and also provides us with default and most importantly right and latest configurations if we don’t specify any. We can always override the default configurations by adding our own and Spring Boot will happily skip that part.

I think in case of Spring Boot, we can really say – Less (no?) Pain, More Gain !

All the code can be found here : Github

How I met Spring Boot…

The title of this blog is inspired from the famous sitcom “How I met your Mother”. Well, this is a short story of How I met Spring Boot.

We are a team of 5 developers among whom there is a so-called “Software Architect”. In this part of the world that I live, the 2 words, “software architect” really mean different things to different people. More on that later.

There was a new requirement to rewrite a system currently maintained using mainframe to a more modern AngularJS/RESTful based application.The back-end would have REST based services which would communicate with an Oracle database using JPA . On the server side, the first task was really to set up the basic back end application and then the developers on the team would start with their use cases. Our architect decided to take up the responsibility of setting up the basic back end and mentioned that it was a tough task. By basic I mean, just the bare bones with all the basic dependencies, configuration against an in memory database to begin with, simple rest service to help the team get up and running.

When the scrum master asked him an estimate , he said he would take around 2 weeks to set up the basic backend code.

Well during the daily stand up meeting, the architect would say that he is still setting up the project and that went on for 2 weeks.At the end of 2 weeks when he checked in the code, what I saw was really shocking. What I saw was strange dependencies, outdated versions of jars, unused code,dependencies. I realized later that he had copy pasted the basic setup from another project.

Well, I said to myself, “Is setting up a project that hard ? I do remember shying away from trying a few things on my own assuming it would be complicated to bring in all the right dependencies, set up the right Spring configuration.I remember I wanted to integrate Spring with Hibernate and never really understood spring-orm library and everything else that came along with it. I have sometimes wondered how to get all configuration right and well sometimes been a little lazy.

But this time,  I decided to investigate this further and decided to set up the project  and of course nobody in the team knew this. This is when I discovered Spring Boot.

Well, as I was browsing through the official Spring framework website, I read something about bootstrapping your Spring Boot application and this is when I stumbled upon the Spring Initializr. I switched to the full version there and chose the following:

  1. Maven project
  2. Java 1.8
  3. Left the group and artifact id as it is as I was playing around.
  4. JPA support
  5. H2 as in memory database and finally
  6. Full stack web development with Tomcat and Spring MVC

And well on clicking the Generate Project button,  I had a full-fledged maven project. That took a few days…Correction – seconds!

I then wrote the following simple classes, one end point for the rest service, one for the repository layer, one JPA entity and finally the class which starts everything.

EmployeeRestController.java


package com.example;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class EmployeeRestController {
private EmployeeRepository employeeRepository;
@Autowired
public EmployeeRestController(EmployeeRepository employeeRepository) {
this.employeeRepository = employeeRepository;
}
@RequestMapping("/employees")
public List<Employee> employees() {
return employeeRepository.findAll();
}
}

EmployeeRepository.java


package com.example;
import org.springframework.data.jpa.repository.JpaRepository;
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
}

Employee.java


package com.example;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String firstName;
private String lastName;
public Employee() {
}
public Employee(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
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;
}
@Override
public String toString() {
return "Employee [firstName=" + firstName + ", lastName=" + lastName + "]";
}
}

view raw

Employee.java

hosted with ❤ by GitHub

DemoApplication.java


package com.example;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication implements CommandLineRunner {
// Use constructor injection.
@Autowired
private EmployeeRepository employeeRepository;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
// Initialization to add data to h2 db.
@Override
public void run(Stringargs) throws Exception {
List<Employee> employees = getAllEmployees();
employees.forEach(employee -> employeeRepository.save(employee));
}
private List<Employee> getAllEmployees() {
List<Employee> employees = new ArrayList<>();
employees.add(new Employee("Barney", "Stinson"));
employees.add(new Employee("Alex", "Hitch"));
employees.add(new Employee("Douglas", "Ramsey"));
return employees;
}
}

Snapshot of the pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<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.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.0.RELEASE</version>
<relativePath/> <!– lookup parent from repository –>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

view raw

pom.xml

hosted with ❤ by GitHub

Then I did the following:

  1. Ran mvn clean install
  2. java -jar ./target\demo-0.0.1-SNAPSHOT.jar ( Yes, that is right, a jar file)

That’s it, the application was up and running ! When I hit the URL :

http://localhost:8080/employees

I got the following output:

[{"firstName":"Barney","lastName":"Stinson"},{"firstName":"Alex","lastName":"Hitch"},{"firstName":"Douglas","lastName":"Ramsey"}]

Note The DemoApplication implements a CommandLineRunner and hence the run method. This is being done only to populate some mock data into the H2 database which the rest service can access .

The entire thing took me only a few minutes. We were able to set up and run a Spring REST, JPA based maven project in a matter of few minutes ! Not just that , we were able to get an executable jar file which ran in an embedded server. Now, how cool is that !

Well, I wonder what the architect did during those 2 weeks what we could do in a few minutes! Not just that, we were able to configure the project with all the latest and relevant dependencies without worrying about compatibility and version related issues.

We did not write a single configuration file, there are no xml’s,  there is absolutely no code generation behind the scenes !

But what really happened ?

This is all handled by Spring Boot ! The starter pom that we added brings in the required jars to the classpath. As an example ,with the spring-boot-starter-parent and spring-boot-starter-data-jpa dependency , Sprint Boot will bring all the latest versions of the jars(Spring data, Hibernate). In our case  it pulls in version 5.0.9 of Hibernate.

Then through the usage of the @SpringBootApplication annotation (see DemoApplication.java)  Spring Boot configures  some defaults.

Some of the defaults in this case:

  1. Spring Boot configures an embedded Tomcat server if we haven’t configured it to run on anything else. This is done since we added the spring-boot-starter-web in  then pom.xml
  2. As we did not specify any other database specific parameters, Sprint boot decided to use an in memory H2 database which we added in the pom.xml
  3. Spring boot configured JPA with Hibernate for us as we added the spring-boot-starter-data-jpa dependency

Of course we can add other specific configurations that we want and in that case Spring Boot will honor that and move out of the way or if we wanted to bring an older version of Hibernate, we just need to modify the pom.xml and add the following:

<hibernate.version>Required_Version</hibernate.version>

We were able to run the application using the java -jar command. This is enabled through the spring-boot-maven-plugin dependency we added in the pom.xml.

We have only scratched the surface of how simple it is get a project up and running with a rest based service along with JPA but Spring Boot can do a lot more for us. Not only did we manage to get it up and running quickly but with all the right dependencies and the setup looks clean !

We can integrate spring boot with a nosql database, jms , apache camel, jersey, cloud foundry, service discovery and even use it to monitor the application in production. Take a look at Spring Initializr for all the cool things it can do.

This article was only meant to introduce you to Spring Boot. Well, Spring Boot is just perfect for a lazy developer like me.

Well Barney Stinson from the sitcom “How I met your mother” always wore a suit and one of his famous quote is “Suit Up”.  Having met Spring Boot, I must say that we must all Boot up…Spring Boot Up !