Spring Boot JPA Kotlin

Spring Boot provides a ready made solution to working with Java Persistence API (JPA). The post discusses how to make a basic web application that reads and writes employees to a database. We can also count how many employees have a certain name. This will all be done using Spring’s JPA features and the Kotlin programming language.

Spring Boot provides us with a data source on its own with very little configuration. Of course, we are free to connect the application to remote databases as well. To get started, we need to fill out some properties in the application.properties file found in src/main/resources

application.properties

spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate5.SpringSessionContext
spring.datasource.driver-class-name=org.hsqldb.jdbcDriver

The first property, spring.jpa.hibernate.ddl-auto=create-drop tells the application to scan for all classes annotated with @Entity and create database tables for us. The persistence provider does the work of generating database definition language (DDL) and creating our database schema for us.

The second property configures Hibernate to act as our persistence provider. This is required because JPA is a specification. It requires a 3rd party library (Hibernate, EclipseLink, etc) to actually implement the specification. Finally, we need to tell the application what JDBC driver to use. This should match our database. In this case, we are using HSQLDB so we load their JDBC driver.

Database Entity

We need to create one or more persistant objects that are mapped to the database. In this case, we only have 1, an Employee Class, that we are using to map to a database table.

//This class maps to a table in the database
//that will get created for us
@Entity
data class Employee(
       @field: Id @field: GeneratedValue var Id : Long = 0, //Primary Key
       var name : String = "", //Column
       var position : String = "") //Column

Kotlin provides data classes for these sort of situations. The first property is annotated with Id and serves as the Primary Key. The GeneratedValue annotation tells the persistence provider to generate primary key values for us. The other two properties, name and position, end up becoming columns in the database table. When persistence provider scans this class, it will issue the correct commands to the database and generate an employee table with an primary key columna and two VARCHAR columns. Each instance of the Employee class that we store will become a record in the table.

Automatic Repositories

Spring is capable of generating @Repository classes for use when working with JPA. These repositories come fully loaded with 18 methods that handle all of our CRUD (create, read, update, and delete) methods and provide container managed transactions. We can even create our own custom queries using a naming convention and Spring will infer what needs to be done.

However, before we can have Spring generate our repositories for us, we need to tell it to do so. That’s pretty easy because all we need is a small configuration class.

Config

@Configuration
//The next line tells Spring Generate our JPA Repositories
@EnableJpaRepositories(basePackages = arrayOf("com.stonesoupprogramming.jpa"))
class Config

The package passed to the @EnableJpaReposities tells Spring where to look for repository interfaces. In order to make a Repository for the Employee class, we only need to declare an interface that extends JpaRepository.

EmployeeRepository

//The Implementation for this class is generated
//by Spring Data!
interface EmployeeRepository : JpaRepository <Employee, Long>{

    //Define a custom query using Spring Data
    fun countByNameContainingIgnoringCase(name : String) : Long
}

At no point will we ever write an implementation for this interface. When Spring sees this interface, it will generate an implementation class that is fully loaded and ready for our application to use. Technically, this interface could be empty, but we do have one method countByNameContainingIgnoringCase(String). Let’s discuss it.

Spring JPA Repositories are capable of defining queries on our persiteted objects provided that we follow the proper naming convention. Let’s take apart countByNameContainingIgnoringCase and discuss what each part means.

  • count — We are defining a count query
  • ByName — The syntax here is By[Property]. Our Employee class has a Name property, so we write ByName. If we wanted to use Position instead, it would be ByPosition
  • ContainingIgnoringCase — This is the predicate of the query. We are looking for anything containing a string value (in this case) and we are ignoring the case.

So in the end countByNameContainingIgnoringCase defines a query that means what it says. We are going to get a count of all records where the name contains a certain name and the name is not case sensitive. Spring is able to parse this name and create the correct query for us.

Put it in Action!

I wrote an MVC application that demonstrates how to use these concepts in a web application. Here is the code for the controller.

@Controller
@RequestMapping("/")
class IndexController(@Autowired private val employeeRepository: EmployeeRepository) {

    @RequestMapping(method = arrayOf(RequestMethod.GET))
    fun doGet(model : Model) : String {
        model.apply {
            addAttribute("employee", Employee())
            addAttribute("showName", false)
            addAttribute("employees", employeeRepository.findAll().toList())
        }
        return "index"
    }

    @RequestMapping("/employee_save", method = arrayOf(RequestMethod.POST))
    fun doEmployeeSave(employee: Employee,
                       model : Model) : String {
        employeeRepository.save(employee)
        model.apply {
            addAttribute("employee", Employee())
            addAttribute("showName", false)
            addAttribute("employees", employeeRepository.findAll().toList())
        }
        return "index"
    }

    @RequestMapping("/employee_count", method = arrayOf(RequestMethod.POST))
    fun doEmployeeCount(@RequestParam("name") name : String,
                        model : Model) : String {
        val count = employeeRepository.countByNameContainingIgnoringCase(name)
        model.apply {
            addAttribute("employee", Employee())
            addAttribute("showName", true)
            addAttribute("count", "Number of employees having name $name: $count")
            addAttribute("employees", employeeRepository.findAll().toList())
        }
        return "index"
    }
}

Even though we never wrote an implementation for EmployeeRepository, we can safely inject an instance of EmployeeRepository into our controller class. From this point, we have an HTTP GET method and two POST methods. The doEmployeeSave calls employeeRepository.save() and saves the incoming Employee object to the database. It also calls employeeRepository.findAll() and sends all employee records back to the view.

The doEmployeeCount calls our custom employeeRepository.countByNameContainingIgnoringCase method and returns a count of how many employee records contain the given name. We can pass this number back to the view. Once again, we are using employeeRepository.findAll().

This is the HTML code that works with the IndexController class.
indexhtml1indexcontroller2

Conclusion

The JPA cababilities provided by Spring Boot make developing ORM applications a breeze and it’s worth while to leverage them. For one thing, we only have to write a fraction of the code that we might have to write otherwise, but we are also less likely to introduce bugs into the application because we can trust the implementation of the JPA Repository classes and the persistence provided SQL generating capabilities.

Here are some screen shots of the finished application.


You can download the code at my GitHub page here or visit the YouTube tutorial.

Advertisements

Kotlin Stream Image from Database

Many web applications allow users to store images for later. For example, you may want to allow users to upload a profile picture that gets displayed later on in the application. This post demonstrates how to upload an image to a web application and store the image in a database. Then we will see how to display that image in a browser.

PersistedImage

The key to storing an image in a database is to use @Lob annotation in JPA and make the datatype as a byte array. Here is an example class that stores byte array in the database.

@Entity
data class PersistedImage(@field: Id @field: GeneratedValue var id : Long = 0,
                          //The bytes field needs to be marked as @Lob for Large Object Binary
                          @field: Lob var bytes : ByteArray? = null,
                          var mime : String = ""){

    fun toStreamingURI() : String {
        //We need to encode the byte array into a base64 String for the browser
        val base64 = DatatypeConverter.printBase64Binary(bytes)

        //Now just return a data string. The Browser will know what to do with it
        return "data:$mime;base64,$base64"
    }

Kotlin has a ByteArray class. In Java you would use byte []. The effect is the same either way. When persistence provider scans this class, it will store the byte array as a Lob in the database. Nevertheless it’s not enough to simply store an image in the database. At some point in time, the user will most likely wish to see the image. That’s there the toStreamingURI() method comes in handy.

The first line uses DatatypeConverter to convert the byte array to a base64 string. Then we can append that string to “data:[mime];base64,[base 64]”. In our example, we use Kotlin’s String template feature to build such a String. We start with the data: followed by the mime (such as /img/png). Then we can add the base64 string created by DatatypeConverter. This string can get added to the src attribute of the html img tag as shown in the screen shot below.

base64string
The browser knows how to display this string as an image.

File Uploads

It’s worth while to discuss how files are upload in Spring. Spring has a MultipartFile class that can get mapped to the a file upload input tag in the form. Here is how it looks in the HTML code.
fileuploadform
There are a couple of things that are critical for this to work. First, we have to set our applications.properties file to allow large file uploads.

spring.http.multipart.max-file-size=25MB
spring.http.multipart.max-request-size=25MB

Next our form tag has to set the enctype attribute to “multipart/form-data”. Finally we have to keep track of the name attribute on our input tag so that we can map it to the server code. In our example, our input tag has it’s name attribute set to “image”.

On the server end, we use this code get an instance of MultipartFile.

@RequestMapping(method = arrayOf(RequestMethod.POST))
    fun doPost(
            //Grab the uploaded image from the form
            @RequestPart("image") multiPartFile : MultipartFile,
               model : Model) : String {
        //Save the image file
        imageService.save(multiPartFile.toPersistedImage())
        model.addAttribute("images", imageService.loadAll())
        return "index"
    }

We annotate the multipartFile parameter with @RequestPart and pass to the annotation the same name attribute that we set on our input tag. At this point, the container will inject an instance of MultipartFile that represents the file that the user uploaded to the server. The MultipartFile class has two attributes that are critical to our purposes. First it has a byte array property that represents the bytes of the uploaded file and it has the file’s MIME.

We can use Kotlin’s extension functions to add a toPersistedImage() method on MutlipartFile.

fun MultipartFile.toPersistedImage() = PersistedImage(bytes = this.bytes, mime = this.contentType)

This method simply returns an instance of PersisitedImage that can get stored in the database. At this point, we can easily store and retrieve the image from the database.

Application

The demonstration application is a regular Spring MVC application written in Kotlin. You can refer to this post on an explanation on how this works. Here is the Kotlin code followed by the HTML code.

Kotlin Code

package com.stonesoupprogramming.streamimage

import org.hibernate.SessionFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.stereotype.Controller
import org.springframework.stereotype.Repository
import org.springframework.stereotype.Service
import org.springframework.ui.Model
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestMethod
import org.springframework.web.bind.annotation.RequestPart
import org.springframework.web.multipart.MultipartFile
import javax.persistence.*
import javax.transaction.Transactional
import javax.xml.bind.DatatypeConverter

@SpringBootApplication
class StreamImageDbApplication

fun main(args: Array) {
    SpringApplication.run(StreamImageDbApplication::class.java, *args)
}

@Entity
data class PersistedImage(@field: Id @field: GeneratedValue var id : Long = 0,
                          //The bytes field needs to be marked as @Lob for Large Object Binary
                          @field: Lob var bytes : ByteArray? = null,
                          var mime : String = ""){

    fun toStreamingURI() : String {
        //We need to encode the byte array into a base64 String for the browser
        val base64 = DatatypeConverter.printBase64Binary(bytes)

        //Now just return a data string. The Browser will know what to do with it
        return "data:$mime;base64,$base64"
    }
}

//This is a Kotlin extension function that turns a MultipartFile into a PersistedImage
fun MultipartFile.toPersistedImage() = PersistedImage(bytes = this.bytes, mime = this.contentType)

@Configuration
class DataConfig {

    @Bean
    fun sessionFactory(@Autowired entityManagerFactory: EntityManagerFactory) :
             SessionFactory = entityManagerFactory.unwrap(SessionFactory::class.java)
}

@Repository
class ImageRepository(@Autowired private val sessionFactory: SessionFactory){

    fun save(persistedImage: PersistedImage) {
        sessionFactory.currentSession.saveOrUpdate(persistedImage)
    }

    fun loadAll() = sessionFactory.currentSession.createCriteria(PersistedImage::class.java).list() as List
}

@Transactional
@Service
class ImageService(@Autowired private val imageRepository: ImageRepository){

    fun save(persistedImage: PersistedImage) {
        imageRepository.save(persistedImage)
    }

    fun loadAll() = imageRepository.loadAll()
}

@Controller
@RequestMapping("/")
class IndexController(@Autowired private val imageService: ImageService){

    @RequestMapping(method = arrayOf(RequestMethod.GET))
    fun doGet(model : Model) : String {
        model.addAttribute("images", imageService.loadAll())
        return "index"
    }

    @RequestMapping(method = arrayOf(RequestMethod.POST))
    fun doPost(
            //Grab the uploaded image from the form
            @RequestPart("image") multiPartFile : MultipartFile,
               model : Model) : String {
        //Save the image file
        imageService.save(multiPartFile.toPersistedImage())
        model.addAttribute("images", imageService.loadAll())
        return "index"
    }
}

application.properties

spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate5.SpringSessionContext
spring.datasource.driver-class-name=org.hsqldb.jdbcDriver

spring.http.multipart.max-file-size=25MB
spring.http.multipart.max-request-size=25MB

index.html

streamimage

Conclusion

Spring and Kotlin make it easy to embed images in a database and display those images in a browser. The main take away is to define a byte array property as a Lob on persisted image and then convert it to a base64 String when you wish to display it. Here are some screen shots of the working application.


You can get the source code for this project at my GitHub here or watch the video tutorial on YouTube.

Kotlin Spring Security Hibernate Login

In a previous post, I showed how we can use Spring Security with JDBC to store user creditionals in a database. This approach works fine in small projects but I find it to be limiting in larger applications. Many larger applications prefer to use some sort of Object Relational Mapping (ORM) library to handle storing mapped objects to a database. This post shows how to configure Spring Security to use Hibernate to look up saved users in a database.

applications.properties

Spring Boot uses an application.properties file to configure the application. By default, Spring Boot provides an embedded datastore for the application. We only need minor configuration to make it work with Hibernate.

spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate5.SpringSessionContext
spring.datasource.driver-class-name=org.hsqldb.jdbcDriver

The first line tells the application to scan any classes marked with the @Entity annotation and create database tables for these objects. The next line configures tells it that we wish to use Hibernate. The final line tells the application which JDBC driver to use to interact with the database.

Mapped Objects

Hibernate (and other ORMS) use decorated objects to map to the database. In many cases, these are simply objects that have a list of fields and getters and setters (POJOs) and overide equals() and hashcode(). In most cases, this ends up causing a lot of boiler plate code. Kotlin provides us with data classes that cut down on the noise.

Roles

Spring Security tracks user roles throughout the application, so we need a class to represent user roles.

@Entity
data class Roles(@field: Id @field: GeneratedValue var id : Int = 0,
                 @field: ManyToOne(targetEntity = SiteUser::class) var user : SiteUser,
                 var role: String = "")

This class defines a POKO (Plain Old Kotlin Object) that represents Roles. It’s very boring, but readers will notice how to annotate fields in Kotlin [@field: [Java Annotation]]. So in the case of @Id, we just use @field: Id. The same holds true for @ManyToOne and other JPA annotations.

SiteUser

Since Spring Security has a User class, I find it to be more readable to name our persistent user as SiteUser.

@FetchProfiles(
        FetchProfile(name = "default",
                fetchOverrides = arrayOf(
                        FetchProfile.FetchOverride(entity = SiteUser::class, association = "roles", mode = FetchMode.JOIN)))
)
@Entity
data class SiteUser (@field: Id @field: GeneratedValue var id : Int = 0,
                     var userName: String = "",
                     var password: String = "",
                     var enabled : Boolean = true,
                     var accountNonExpired: Boolean = true,
                     var credentialsNonExpired: Boolean = true,
                     var accountNonLocked : Boolean = true,
                     @field: OneToMany(targetEntity = Roles::class) var roles: MutableSet = mutableSetOf()){

    //Convert this class to Spring Security's User object
    fun toUser() : User {
        val authorities = mutableSetOf()
        roles.forEach { authorities.add(SimpleGrantedAuthority(it.role)) }
        return User(userName, password,enabled, accountNonExpired, credentialsNonExpired, accountNonLocked,authorities);
    }
}

This is another data class with JPA mappings. The SiteUser class have a one to many relationship to Roles (in other words, one user can have multiple roles). Hibernate lazily loads collections by default, so unless we explicilty tell it to eager fetch our user roles, we will get a proxy error later on the in application.

There are several ways to work around this issue. We can use HQL (Hibernate Query Language) to eagerly load Roles. Another solution it to pass FetchType.Eager argument to the OneToMany annotation. A final approach is the one seen here and that’s to use Fetch Profiles to instruct Hibernate what to load. One advantage of FetchProfiles is that a class can have multiple fetch profiles, so using FetchProfiles is a highly flexible solution.

The other thing to note about this class is how to hooks into Spring Security. This class has a toUser() method which is a utility method that converts our SiteUser object into a Spring Security User object. If you look closely, the fields on our SiteUser class are the exact same fields as the User class. This makes it really easy to convert a SiteUser to a User.

Since we configured the application.properties to generate our database DDL (spring.jpa.hibernate.ddl-auto=create-drop), Hibernate will see to the details of scanning our Roles and User class and generated the necessary database tables for us. There is no further work for us to do at this point regarding the data store.

Data Configuration

Our next job is to provide Spring Security with a path to look up Users from the database.

DataConfig

Spring Security needs a path to the database in order to look up User objects. That means we are going to need Repository and Service classes in the application, but those classes depend on a SessionFactory object from Hibernate.

@Configuration
class DataConfig {
    @Bean
    fun sessionFactory(@Autowired entityManagerFactory: EntityManagerFactory) :
            SessionFactory = entityManagerFactory.unwrap(SessionFactory::class.java)
}

We really just need a bean definition for a SessionFactory. Spring Boot is configured to use JPA (Java Persistence Api), which is the ORM standard that Hibernate and other ORM libraries implement. There two main advantages of using the standard JPA rather than vendor API.

  1. Other developers are likely to know the standard API over vendor specific APIs
  2. You can swap ORM libraries when sticking to the standard

In reality, I have never been on a project that switched ORM libraries and there are times when an ORM library offers features that aren’t offered in a standard. Since we know that we are going to use Hibernate, we can just unwrap the SessionFactory object from the injected entityManagerFactory and just return the SessionFactory. At this point, we can inject SessionFactory into our classes and use Hiberante API directly.

UserRepository

UserRepository works directly with the database.

@Repository
//Inject SessionFactory into this class
class UserRepository(@Autowired private val sessionFactory: SessionFactory){

    //Used to save new users into the datastore
    fun saveOrUpdate(user: SiteUser){
        sessionFactory.currentSession.saveOrUpdate(user)
    }

    //Query the database by user name and return a SiteUser that matches
    //the user name
    fun loadByUsername(userName: String) : SiteUser =
            sessionFactory.currentSession.createCriteria(SiteUser::class.java, "su")
                    .add(Restrictions.eq("su.userName", userName)).uniqueResult() as SiteUser

    //Return all Site Users from the database
    fun allUsers(profile : String = "default") : List {
        val session = sessionFactory.currentSession
        session.enableFetchProfile(profile)
        return session.createCriteria(SiteUser::class.java).list() as List
    }
}

You will notice that we inject SessionFactory into this class. Spring Security needs to query the database by the UserName, so loadByUsername uses Hibernate’s Criteria API to create a query that searches for users that match the user name. The other two methods in this class are not related to Spring Security but are used by the application. The saveOrUpdate() method is used to persist a new user into the databse. The allUsers() method returns all users stored in the database.

UserService

The UserService class provides the glue between Spring Security and the Database.

@Transactional //Have Spring Manage Database Transactions
@Service //Mark this class as a Service layer class
class UserService(@Autowired private val userRepository: UserRepository) //Inject UserRepository into this class
    : UserDetailsService { //To work with Spring Security, it needs to implement UserDetailsService

    //Load a user by user name and call our toUser() method on SiteUser
    override fun loadUserByUsername(userName: String): UserDetails  = userRepository.loadByUsername(userName).toUser()

    //Saves a new user into the datastore
    fun saveOrUpdate(user : SiteUser){
        //Encrypt their password first
        user.password = BCryptPasswordEncoder().encode(user.password)

        //Then save the user
        userRepository.saveOrUpdate(user)
    }

    //Return all users
    fun allUsers() = userRepository.allUsers()
}

Spring provides container managed transactions when a class is marked @Transactional. The important part of this class is that it implements UserDetailsService, which allows this class to get passed to Spring Security when we configure our authentication (next section). The loadByUsername method comes from the UserDetailsService interface. It returns a User object, which means we need to call our toUser() method that we defined on SiteUser() to convert SiteUser() to User().

The other method of interest is the saveOrUpdate() method. You will notice that we encrypt our User’s password prior to saving the object to the database. This is a critical step because without it, anyone could peek into our database and get our users password. We also need to encrypt the passwords because we configure our authentication to decrypt passwords later on.

Configuring Spring Security

Now that we have a path that allows the application to access and retreive users from the databse, we are ready to configure Spring Security.

SecurityConfig

The SecurityConfig class does the work of configuring our Spring Security in this application.

@Configuration
class SecurityConfig(@Autowired private val userService : UserService) : //Inject UserService
        WebSecurityConfigurerAdapter() { //Extend WebSecurityConfigureAdaptor

    //Override this method to configure Authentication
    override fun configure(auth: AuthenticationManagerBuilder) {
        auth
                .userDetailsService(userService) //We pass our userService to userDetailsService
                .passwordEncoder(BCryptPasswordEncoder()) //Pass our Encryption Scheme also
    }

    override fun configure(http: HttpSecurity) {
        http.
                formLogin()
                    .and()
                .httpBasic()
                    .and()
                .authorizeRequests()
                    .antMatchers("/display").authenticated()
                    .anyRequest().permitAll()

    }
}

The configure(AuthenticationManagerBuilder) is our method of interest. The auth object has a userDetailsService method that accepts any class that implements UserDetailsService. Since our UserService class implements this interface, it can be used as a value for the userDetailsService method. At that point, our Security is linked to our database. The other method is passwordEncoder that takes an instance of ByCryptPasswordEncorder(), the same class used UserService to encrypt our passwords. Now the AuthenticationManagerBuilder can speak to our database and decode our passwords.

Controller Class

At this point, our application is configured to work Spring Security and a database. Our next two classes setup Spring MVC so that we have a working example.

RegisterController

RegisterController is used to add users to the application.

@Controller
@RequestMapping("/register")
class RegisterController(@Autowired private val userService: UserService){

    @RequestMapping(method = arrayOf(RequestMethod.GET))
    fun doGet(model: Model) : String{
        model.addAttribute("user", SiteUser())
        return "register"
    }

    @RequestMapping(method = arrayOf(RequestMethod.POST))
    fun doPost(siteUser: SiteUser) : String{
        userService.saveOrUpdate(siteUser)
        return "redirect:/display"
    }
}

UserDisplay

UserDisplay controls the display page and shows all users in our database.

@Controller
@RequestMapping("/display")
class UserDisplay(@Autowired private val userService: UserService){

    @RequestMapping(method = arrayOf(RequestMethod.GET))
    fun doGet(model: Model) : String{
        model.addAttribute("users", userService.allUsers())
        return "display"
    }
}

Web Pages

Finally we have our web pages. One page allows us to register a user, and the other one shows all of our users.

register.html

registercode

display.html

displaycode

Conclusion

Here are some screenshots of what the working site looks like when finished.


As you can see, Spring Security works fluently with ORM solutions such as Hibernate. This makes it much easier to add and retreive users in a web application!

You can clone the full source for this project from my GitHub page here or view the YouTube view here.