No description, website, or topics provided.
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
.mvn/wrapper
src
.gitignore
LICENSE
README.md
mvnw
mvnw.cmd
pom.xml

README.md

kotlin-spring-boot-lab

Welcome to the Spring Boot Kotlin lab. We're going to learn some of the Kotlin syntax and features while developing a Spring Boot app. This lab is inspired on the Spring Boot Kotlin Tutorial, with more references to the Kotlin language features used and the format and scope adapted to a lab of one to one and half hours. Please follow the steps below.

Install IntelliJ

Kotlin is a language developed by JetBrains, the company behind IntelliJ, so even though you can use any text editor, IntelliJ is recommended due to better integration with the language. Please, download and install the Ultimate or Community edition.

Bootstrap your application

  1. Go to Spring Initializr
  2. Select Kotlin as a language
  3. Use "blog" for Artifact
  4. For dependencies, select: Web, JPA, and H2 Spring Initializr
  5. Click on Generate Project
  6. Unpack the downloaded project
  7. On command line run the application with ./mvnw spring-boot:run

Import the project on IntelliJ

  1. File -> new -> Project from existing sources
  2. Select the project folder
  3. Chose "Import project from external model" -> Maven
  4. Follow the next screens and Finish

Look at the application bootstrapped

  1. Open the file com.example.blog.BlogApplication. There are a few things you can notice:
    • Lack of semicolons
    • Since the class has no body, the curly braces can be omitted
    • The main function is a top-level function, meaning there's no need to create a class to hold it, like languages such as Java, C# or Scala
    • The default visibility is public, which can be omitted for the main function
    • If you navigate to the declaration of runApplication, you'll see that it's declared in a Kotlin extension class. It's part of the Spring Boot Kotlin support, enabling writing more idiomatic code
  2. Open the pom.xml file. There are a few things you can notice:
    • kotlin-maven-plugin: used to compile Kotlin code. sourceDirectory and testSourceDirectory are also configured
    • kotlin-maven-allopen: Kotlin has classes and their members final by default, which makes it inconvenient to use frameworks such as Spring that require classes to be open. The all-open plugin, which has Spring support, makes classes annotated with a specific annotation and their members open without the explicit open keyword

Create the first Rest Resource

  1. Implement the class HelloWorldResource
  2. Re-run the application with ./mvnw spring-boot:run
  3. Open your browser on http://localhost:8080/hello. You should see "Hello" on the page displayed.

Understanding the code

  • hello() is a single-expression function, so the curly braces can be omitted
  • For single-expression functions, explicitly declaring the return type is optional when this can be inferred by the compile

Create the Article model and Resource

  1. Implement the Article class with the properties title and content
  2. Implement the ArticleResource Rest endpoint returning a list of Articles.
  3. Re-run the application with ./mvnw spring-boot:run
  4. Open your browser on http://localhost:8080/article. You should see the JSON representation of the list returned

Understanding the code

  • Article
    • Is a class whose main purpose is to hold data, making it a good candidate to be a Data Class, which automatically provide equals(), hashCode(), toString(), componentN() and copy() functions
    • It uses its primary constructor to declare and initialize its properties in a concise way. Properties declared in the primary constructor can be mutable (var) or read-only (val)
  • ArticleResource
    • To create instances of the Article class, we call the constructor as if it was a regular function
    • Kotlin does not have a new keyword
    • listOffunction is part of Kotlin Standard Library, which provides living essentials for everyday work with Kotlin
    • You didn't have to import listOf. Just like Java has java.lang, Kotlin has some packages that are imported by default

Add Article properties with default values

  1. Add the properties createdAt of type LocalDateTime and id of type Long? with default values
  2. Re-run the application with ./mvnw spring-boot:run
  3. Open your browser on http://localhost:8080/article. You should see the new properties on the objects in the list

Understanding the code

  • Function arguments can have default values, which are used when a corresponding argument is omitted
  • Kotlin's type system is aimed at eliminating the danger of null references from code. Since the Article.id is only specified when it's persisted (to be implemented in a following section), its supposed to allow null, so the nullable Long? is used
  • Since we are satisfied with the default values of the new parameters, we do not need to change the Article instantiation on Articleget.getArticles()

Test with JUnit 5

While JUnit 4 is still the default testing framework provided with Spring Boot, and can be used with Kotlin, JUnit 5 provides features handy with Kotlin, including autowiring of constructor / method parameters which allows to use non-nullable val properties and the possibility to use @BeforeAll/@AfterAll on regular non-static methods. Follow the steps below, or, to make it easier, see the necessary changes in this diff or the expected final file content: pom.xml and BlogApplicationTests.kt

  1. Exclude junit Maven transitive dependency from spring-boot-starter-test
  2. Add junit-jupiter-engine Maven dependency
  3. Add junit-platform-surefire-provider Maven dependency to maven-surefire-plugin
  4. Refactor BlogApplicationTests.kt to Junit 5
  5. Run ./mvnw clean install and check if the build is still successful

Add test to ArticleResource

  1. Implement the ArticleResourceTest. Make sure to put it in the src/test/kotlin/com/example/blog/ folder. This short test is enough for the purpose of this lab, but I hope in real life you test more than the result size
  2. Run ./mvnw clean install and check if the test runs and the build is still successful

Understanding the code

  • We're using SpringExtension which is able to inject dependencies into test constructors. This makes it a good fit with Kotlin immutable and non-nullable properties
  • We use real sentences in test function names. Backticks are part of the language to help with the Java interop but they also help writing more expressive test function names, instead of the usual camel-case naming
  • getForEntity is another Spring Kotlin extension. It takes advantage of Kotlin reified type parameters, overcoming Java type erasure limitation which would require the usage of ParameterizedTypeReference<List<Article>>
  • response.body?.size is a safe way of accessing the nullable body property. It will return size if body is not null, and null otherwise. Other ways are also available, such as if statments and the Elvis operator

Persistence with JPA

  1. Annotate Article with @Entity and Article.id with @Id @GeneratedValue. Final result: Article
  2. Implement ArticleRepository
  3. Use the ArticleRepository to retrieve the list of Articles on ArticleResource
  4. Add the Kotlin JPA plugin and add kotlin-maven-noarg dependency to the pom.xml`
  5. Re-run the application with ./mvnw spring-boot:run
  6. Open your browser on http://localhost:8080/article. The result is not very exciting and you won't see anything since the database is empty. We'll solve this on next section

Understanding the code

  • JPA annotations can be used in the primary constructors, contributing for a concise code
  • Primary constructors will also have its dependencies automatically autowired, which is the case of ArticleResource
  • JPA requires the entities to have a zero-argument constructor. Since we added the primary constructor to Article, the entity is no longer satisfying that requirement. Kotlin no-arg plugin with JPA support adds a zero-argument constructor for classes annotated with @Entity, @Embeddable and @MappedSuperclass

Add some Articles to the database

  1. Implement the function BlogApplication.initDatabase()
  2. Re-run the application with ./mvnw spring-boot:run
  3. Open your browser on http://localhost:8080/article. Now you should see some Articles on the page

Understanding the code

  • Now that BlogApplication has a body, it needs curly braces
  • The function initDatabase produces a @Bean of type CommandLineRunner which implements a callback to run specific pieces of code when an application is fully started
  • CommandLineRunner is a FunctionalInterface, meaning it's a Single Abstract Method (SAM) interface, which can be automatically converted from Kotlin function literals. If it got too complicated, the bottom line is the Kotlin support for functional programming allows us to implement the method the way we did, instead of having to explicitly declare a class to implement a single method

Review

So that's it for now. Even though we haven't implemented the most exciting application, the small portion of code we wrote was able to introduce some key Kotlin features, such as:

  • Basic syntax, e.g., class and function declaration, class instantiation, etc.
  • Top-level functions
  • Single-expression functions and optional return declaration
  • Data classes
  • Primary constructors
  • Kotlin Standard Library
  • Default imports
  • Function parameters default values
  • Nullable and non-nullable types
  • Reified type parameters
  • Lambda Expressions and function literals
  • JUnit 5 integration
  • JPA integration
  • Kotlin Maven plugins
  • Spring Kotlin extensions