Feb 2, 2021

Loading Local Test Data in Spring Boot

When working on an API, it can be nice to load some data locally on startup. This is especially true when working on a read-only endpoint where no REST API is available to POST any new data. There’s a few different ways to load data in Spring Boot, so this post will walk you through the options and give my preferred approach.

🚀 Your first step is to look at the Spring Boot Docs, where you see that the recommended approach is to use a data.sql file (or import.sql if you have Hibernate ddl-auto manage your tables). So, thinking that’s a good idea, you might write up something like:

merge into MY_OBJECTS values ('e166755b-2b99-43e4-bf64-74ddff84d064', 'abc', '123');
merge into MY_OBJECTS values ('bbe14733-6db7-4f15-ab3a-13fd0e29d397', 'def', '456');
merge into MY_OBJECTS values ('7cebd07b-2334-4c6d-baf9-efe194ae29a5', 'xyz', '789');

⚠️ This works fine for small pieces of data, or for very simple tables, but you’ll notice a few problems that come with this approach:
1) Generated IDs and UUID’s will be complicated
2) Any Spring data validation rules will be missed
3) Enums will not be respected
4) Difficult to reference data from other tables

☕ Then maybe, like me, you miss the Grails way of having a Bootstrap.groovy class that gets magically called at system startup? Grails would run this script file after startup before serving the application, and it was a great place to add test local data.

And this is how I felt for a long time, that Spring Boot just didn’t have an easy way to do something similar. Until I had a Twitter conversation, where it was shown to me about using an ApplicationRunner.java class.

But interestingly when I dove back into the Spring Docs to find more info, there’s really only an obscure reference to ApplicationRunner.java, and even then there isn’t an example of how to use it.

📝 So here’s my take at using ApplicationRunner to bootstrap some SpringBoot data:

This fixes all of my complaints about data.sql from above:
1) The ID is not specified, so UUID will get auto-generated
2) It uses the Repository class to save, along with using an Entity Validations
3) If this class needed to use an Enum we could easily reference it
4) We can do other table operations first, like only insert the data if the table is empty

❗Note a couple of other things:
A) The @Profile annotation specifies to only run this for the local and test profiles. These are fairly common custom profiles to have, but you’ll need to setup your application to use these (or others) if you don’t have them already.
B) I’m using Lombok to auto generate the constructor. You don’t have to use Lombok, if you love typing lots of boilerplate, so you can remove that annotation and write your own constructor.

This certainly isn’t for every application, so just take it as a tool to add to your toolbox. But I’m mostly writing this because I was surprised that the concept was around for many years now and somehow I had just never stumbled upon it, until now!

About the Author

Jeff Sheets profile.

Jeff Sheets

VP - Technology

Jeff has developed Java, Groovy, Grails, and Javascript web apps for industries as varied as Defense, Energy, Weather, Insurance, and Telecom. He is a co-organizer of the Omaha Java Users Group. Jeff has worked on Grails projects since the Grails 1.3.x days, and has experience with production Groovy code as well as Spock tests and Gradle builds. His latest focus has been on AngularJS and Spring Boot applications using JHipster. Jeff also enjoys volunteering at local CoderDojo events to teach programming to our next generation.

Leave a Reply

Your email address will not be published. Required fields are marked *

Related Blog Posts
Feature Flags in Terraform
Feature flagging any code can be useful to developers but many don’t know how to or even that you can do it in Terraform. Some benefits of Feature Flagging your code You can enable different […]
Infrastructure as Code – The Wrong Way
You are probably familiar with the term “infrastructure as code”. It’s a great concept, and it’s gaining steam in the industry. Unfortunately, just as we had a lot to learn about how to write clean […]
Snowflake CI/CD using Jenkins and Schemachange
CI/CD and Management of Data Warehouses can be a serious challenge. In this blog you will learn how to setup CI/CD for Snowflake using Schemachange, Github, and Jenkins. For access to the code check out […]
How to get your pull requests approved more quickly
TL;DR The fewer reviews necessary, the quicker your PR gets approved. Code reviews serve an essential function on any software codebase. Done right, they help ensure correctness, reliability, and maintainability of code. On many teams, […]