Bootstrapping data with Spring
So you find yourself working on a 'traditional' Java Spring project, and you need some reference data pre-populated into your database.
In Grails this is quite easy - just crack open bootstrap.groovy
and start creating new entities.
Fortunately, we can create a similar mechanism using an InitializingBean
and a bit of pre-conditional checking.
Bean Class
In our example application, we need a system user and a bunch of country codes added to our database. This can always be expanded to read lists from xml/csv files, but keeping things simple for this example.
Each individual function is responsible for checking if it's data is required to be bootstrapped, or if it always has been.
@Service
public class BootstrapDataPopulator implements InitializingBean {
private final Logger LOG = LoggerFactory.getLogger(BootstrapDataPopulator.class);
@Autowired
UserRepository userRepository;
@Autowired
CountryCodeRepository countryCodeRepository;
@Override
@Transactional()
public void afterPropertiesSet() throws Exception {
LOG.info("Bootstrapping data...");
createSystemUser();
createCountryCodes();
LOG.info("...Bootstrapping completed");
}
private void createSystemUser() {
if (userRepository.getSystemUser() != null) {
return;
}
LOG.info("... creating system user");
User user = new User();
user.setUsername(userRepository.getSystemUsername());
user.setFirstName("System");
user.setLastName("User");
userRepository.saveAndFlush(user);
}
private void createCountryCodes() {
if (countryCodeRepository.count() > 0) {
return;
}
LOG.info("... creating Country codes");
List<CountryCode> codes = new ArrayList<>();
codes.add(new CountryCode(1, "AU", "Australia"));
codes.add(new CountryCode(2, "USA", "United States of America"));
codes.add(new CountryCode(3, "NZ", "New Zealand"));
countryCodeRepository.save(codes);
countryCodeRepository.flush();
}
}
Bean Declaration
In the above example, we are using the @Service
annotation to initialize the bean, but there is no reason you can't declare the bootstrap bean more explicitly.
Logs for Logging logs
The advantage of the 'individual function' sort of pattern is you easily see what parts of the bootstrapping process are occuring
E.g. on first run:
Bootstrapping data...
... creating system user
... creating Country codes
...Bootstrapping completed
And subsequent runs:
Bootstrapping data...
...Bootstrapping completed