Elegant Data Initialization for Spring Projects

So you want some initial data to be available to your spring project. You can use Hibernate's import.sql but let's do it with Java 8 and Spring Data JPA Repositories.

Case: Make sure there is an admin user, if not create one with desired roles. (Sample Data: username: admin, password:admin and has ROLE_USER, ROLE_ADMIN roles)

Model:

@Entity
public class Role {
    @Id
    private Long id;
    private String name;
    private String description;
}

@Entity
public class User {
    @Id
    private Long id;
    private String username;
    private String password;
    @ManyToMany
    private Set<Role> roles = new HashSet<>();
}

Data JPA Repositories:

public interface RoleRepository extends CrudRepository<Role, Long> {
    Optional<Role> findByName(String name);
}

public interface UserRepository extends CrudRepository<User, Long> {
    Optional<User> findByUsername(String username);
}

Initialize Data:


@Component
public class Bootstrap implements InitializingBean {

    @Autowired RoleRepository roleRepo;
    @Autowired UserRepository userRepo;

    @Override
    public void afterPropertiesSet() throws Exception {
        Role roleUser= roleRepo.findByName("ROLE_USER")
                .orElseGet(() -> 
                    roleRepo.save(new Role("ROLE_USER", "User Role description"))
                );

        Role roleAdmin = roleRepo.findByName("ROLE_ADMIN")
                .orElseGet(() -> 
                    roleRepo.save(new Role("ROLE_ADMIN", "Administrator Role description"))
                );

        User user = userRepo.findByUsername("admin").orElseGet(() -> {
            User u = new User("admin", "admin");
            u.getRoles().add(roleUser);
            u.getRoles().add(roleAdmin);
            return userRepo.save(u);
        });
    }
}

  • We make the class a @Component implementing InitializingBean interface. This will make sure afterPropertiesSet() method will be called for each startup, after the injections are complete.

  • Since our repositories return Optional values, we can use orElseGet on them to create domain objects if they don't already exist in the database. This was the Grails' way of writing bootstrap.groovy files. Don't know if it is still the case.

  • Above classes are simplified to give you the main point. Real life code probably will use Spring Security GrantedAuthority and UserDetails interfaces, and a password encoder.