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
An Exploration in Rust: Musings From a Java/C++ Developer
Why Rust? It’s fast (runtime performance) It’s small (binary size) It’s safe (no memory leaks) It’s modern (build system, language features, etc) When Is It Worth It? Embedded systems (where it is implied that interpreted […]
Getting Started with CSS Container Queries
For as long as I’ve been working full-time on the front-end, I’ve heard about the promise of container queries and their potential to solve the majority of our responsive web design needs. And, for as […]
Simple improvements to making decisions in teams
Software development teams need to make a lot of decisions. Functional requirements, non-functional requirements, user experience, API contracts, tech stack, architecture, database schemas, cloud providers, deployment strategy, test strategy, security, and the list goes on. […]
JavaScript Bundle Optimization – Polyfills
If you are lucky enough to only support a small subset of browsers (for example, you are targeting a controlled set of users), feel free to move along. However, if your website is open to […]