Spring Boot application with RESTEasy, Exposed, SQL Server written in Kotlin

Ken Wonoatmojo
Jun 6 · 4 min read

Recently we have an opportunity to do a bit of exercise in freshening up our API tech stack especially in the microservices area. Our current tech stack is generally using Spring, RESTEasy, JPA (Hibernate) running on Tomcat written in Java 8 language. We want to transition to the embedded microservices world and see how Spring Boot fits into this plan with Kotlin as the new language of choice.

In this exercise, we want to replace Java with Kotlin, Tomcat with embedded Spring Boot , JPA(Hibernate) with Exposed while keeping RESTEasy, Spring Transaction, and Spring core framework as the glue to keep everything together. The architecture diagram below described how every component fits in the picture.

As our build tool, we will be using the old trusted Apache Maven.

Creating Spring Boot app

As our base app, we are using the example Spring Boot app written in Kotlin from the Spring team.

Follow the tutorial and get the sample app running. This sample app is using Spring REST controller and JPA(Hibernate) running on H2 in-memory database

Adding RESTEasy

Next, we are going to replace Spring REST controller with RESTEasy. We will be using the RESTEasy Spring boot starter project.

pom.xml

Add the following dependency to the pom file.

<dependency>
  <groupId>javax.ws.rs</groupId>
  <artifactId>javax.ws.rs-api</artifactId>
  <version>2.1</version>
</dependency>
<dependency>
  <groupId>org.jboss.resteasy</groupId>
  <artifactId>resteasy-spring-boot-starter</artifactId>
  <version>3.0.0.Final</version>
  <scope>runtime</scope>
</dependency>

RestEasyApplication.kt

Create a Kotlin file with the following content

import org.springframework.stereotype.Component
import javax.ws.rs.ApplicationPath
import javax.ws.rs.core.Application

@Component
@ApplicationPath("/rest-easy/")
class RESTEasyApplication : Application()

application.yaml

For RESTEasy integration, we will be using application.yaml format rather than properties

resteasy:
  jaxrs:
    app:
      registration: property
      classes: com.example.blog.RESTEasyApplication
management:
  endpoints:
    web:
      exposure:
        include:
          - health
          - shutdown
  endpoint:
    shutdown:
      enabled: true
logging:
  level:
    org:
      springframework: info

RESTEasy End Point

Create another file to describe our REST end point

import org.springframework.stereotype.Component
import javax.ws.rs.Consumes
import javax.ws.rs.GET
import javax.ws.rs.POST
import javax.ws.rs.Path
import javax.ws.rs.Produces
import javax.ws.rs.core.MediaType
import javax.ws.rs.core.Response

@Path("/blog")
@Component
@Produces(MediaType.APPLICATION_JSON)
class EchoEndpoint {

  @GET
  fun echoGET(): Response {
    return Response.ok().entity(Message("Hello world!")).build()
  }

}

Result

Build the app and run it. Go to the URL http://localhost:8080/rest-easy/blog/ and you should see the hello world message

Connecting to SQL Server using Exposed

Next we’ll try to connect our API to a SQL Server database using Exposed. We will also use spring transaction to manage db transactions and spring datasource to manage our db connection

Following on our base example app, create a table called articles in a test SQL Server database with the same structure. Insert a few test records into this table.

pom.xml

Add sql server jdbc driver and exposed dependencies

<dependency>
  <groupId>com.microsoft.sqlserver</groupId>
  <artifactId>mssql-jdbc</artifactId>
  <version>7.2.0.jre8</version>
</dependency>
<dependency>
  <groupId>org.jetbrains.exposed</groupId>
  <artifactId>exposed</artifactId>
  <version>0.13.7</version>
</dependency>
<dependency>
  <groupId>org.jetbrains.exposed</groupId>
  <artifactId>spring-transaction</artifactId>
  <version>0.13.7</version>
</dependency>

Disconnect sample H2 DB

Comment out the db initialization steps done in BlogConfiguration.kt. Remove the h2 dependency from pom

Enable Spring datasource

Add the entry below to the application.yaml file

spring:
  datasource:
    url: jdbc:sqlserver://${sqlserver.url};instanceName=${sqlserver.instance};databaseName=${sqlserver.db.name}
    username: ${sqlserver.db.username}
    password: ${sqlserver.db.password}
    driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver

logging:
  level:
    org:
      springframework: info
      jdbc:
        datasource:
          DataSourceTransactionManager: DEBUG
      jetbrains:
        exposed:
          SpringTransactionManager: DEBUG

The db connection detail will be passed in as environment variables at runtime.

Enable Spring Transaction

@SpringBootApplication
@EnableTransactionManagement
@EnableConfigurationProperties(BlogProperties::class)
class BlogApplication  {

  @Bean
  open fun transactionManager(dataSource: DataSource) = SpringTransactionManager(dataSource)

}

Exposed Table definition

Define our SQL Server tables in Kotlin

import org.jetbrains.exposed.sql.Table
import java.time.LocalDateTime

class Article(
    val id: Long,
  var title: String,
  var headline: String,
  var content: String,
  var slug: String = title.toSlug(),
  var addedAt: LocalDateTime = LocalDateTime.now()
  )

object Articles : Table() {
  val id = long("id").autoIncrement().primaryKey()
  val title = text("title")
  val headline = text("headline")
  val content = text("content")
}

Spring repositories

interface ArticleRepository  {
 fun findAll(): List<Article>
}import org.jetbrains.exposed.sql.ResultRow
import org.jetbrains.exposed.sql.selectAll
import org.springframework.stereotype.Repository
import org.springframework.transaction.annotation.Transactional

@Repository
@Transactional
class ArticleRepositoryImpl: ArticleRepository {

  private fun fromRow(r: ResultRow) =
    Article(r[Articles.id], r[Articles.title], r[Articles.headline], r[Articles.content])

  override fun findAll() = Articles.selectAll().map { fromRow(it) }
}

RESTEasy End Point

Add another end point to fetch articles from SQL Server database

@Autowired
lateinit var repository: ArticleRepository@GET
@Path("/article")
fun articleGET(): Response {
  var articles = repository.findAll();
  return Response.ok().entity(articles).build()
}

Result

Run the application. Remember to pass in the db connection detail

java -Dsqlserver.url=[db-server] -Dsqlserver.instance=[db-instance] -Dsqlserver.db.name=[db-name] -Dsqlserver.db.username=[db-username] -Dsqlserver.db.password=[db-password] -jar .\target\blog-0.0.1-SNAPSHOT.jar

Open a browser and go to URL http://localhost:8080/rest-easy/blog/article.

Project sample code of this blog is available at

Closing thoughts & next steps

This exercise is the beginning of our learning on the Spring Boot, RESTEasy, and Exposed tech stack. So far this stack looks promising given that we are able to accomplished this much in a reasonable period of time without major roadblocks. There are plenty of examples on the web and this stack seems to be very well supported in the community. This is one stack which we’ll strongly consider for our production development.

Next steps include optimising Spring datasource, reducing Spring Boot footprint (starter project includes many other dependencies), disabling Spring annotation scanning for faster application start up.

Code道

The Tao (Chinese: 道; pinyin: Dào; literally: “the Way” ) Code道— is a publication about all things app development. Our way — Learn through sharing

Ken Wonoatmojo

Written by

Code道

Code道

The Tao (Chinese: 道; pinyin: Dào; literally: “the Way” ) Code道— is a publication about all things app development. Our way — Learn through sharing