DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Because the DevOps movement has redefined engineering responsibilities, SREs now have to become stewards of observability strategy.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Related

  • Be Punctual! Avoiding Kotlin’s lateinit In Spring Boot Testing
  • Improving Backend Performance Part 1/3: Lazy Loading in Vaadin Apps
  • Develop a Secure CRUD Application Using Angular and Spring Boot
  • Building Mancala Game in Microservices Using Spring Boot (Part 3: Web Client Microservice Implementation Using Vaadin)

Trending

  • Useful System Table Queries in Relational Databases
  • Introducing Graph Concepts in Java With Eclipse JNoSQL, Part 2: Understanding Neo4j
  • Securing the Future: Best Practices for Privacy and Data Governance in LLMOps
  • Is Big Data Dying?
  1. DZone
  2. Coding
  3. Frameworks
  4. Playing With Spring Boot, Vaadin, and Kotlin

Playing With Spring Boot, Vaadin, and Kotlin

Spring Boot and Vaadin enthusiast, Nicolas Frankel, takes us through building an application in the JVM language Kotlin, using the two frameworks.

By 
Nicolas Fränkel user avatar
Nicolas Fränkel
DZone Core CORE ·
Jan. 15, 16 · Tutorial
Likes (9)
Comment
Save
Tweet
Share
29.8K Views

Join the DZone community and get the full member experience.

Join For Free

It’s no mystery that I’m a fan of both Spring Boot and Vaadin. When the Spring Boot Vaadin add-on became GA, I was ecstatic. Lately, I became interested in Kotlin, a JVM-based language offered by JetBrains. Thus, I wanted to check how I could develop a small Spring Boot Vaadin demo app in Kotlin – and learn something in the process. Here are my discoveries, in no particular order.

Spring Needs Non-final Stuff

It seems Spring needs @Configuration classes and @Bean methods to be non-final. As my previous Spring projects were in Java, I never became aware of that because I never use the final keyword. However, Kotlin classes and methods are final by default: hence, you have to use the open keyword in Kotlin.

@Configuration
open class AppConfiguration {
    @Bean
    @UIScope
    open fun mainScreen() = MainScreen()
}

No Main Class

Spring Boot applications require a class with a public static void main(String... args) method to reference a class annotated with @SpringBootApplication. In general, those two classes are the same.

Kotlin has no concept of such static methods, but offers pure functions and objects. I tried to be creative by having an annotated object referenced by a pure function, both in the same file.

@SpringBootApplication
open class BootVaadinKotlinDemoApplication

fun main(vararg args: String) {
    SpringApplication.run(arrayOf(BootVaadinKotlinDemoApplication::class.java), args)
}

Different Entry-point Reference

Since the main function is not attached to a class, there’s no main class to reference to launch inside the IDE. Yet, Kotlin creates a .class with the same name as the file name suffixed with Kt.

My file is named BootVaadinKotlinDemoApplication.kt, hence the generated class name is BootVaadinKotlinDemoApplicationKt.class. This is the class to reference to launch the application in the IDE. Note that there’s no need to bother about that when using mvn spring-boot:run on the command-line, as Spring Boot seems to scan for the main method.

Short and Readable Bean Definition

Java syntax is seen as verbose. I don’t think it’s a big issue when its redundancy is very low compared to the amount of useful code. However, in some cases, even I have to admit it’s a lot of ceremony for not much. When of such case is defining beans with the Java syntax:

@Bean @UIScope
public MainScreen mainScreen() {
    return new MainScreen();
}

Kotlin cuts through all of the ceremony to keep only the meat:

  • No semicolon required
  • No new keyword
  • Block replaced with an equal sign since the body consists of a single expression
  • No return keyword required as there’s no block
  • No return type required as it can easily be inferred
@Bean @UIScope
fun mainScreen() = MainScreen()

Spring configuration files are generally quite long and hard to read. Kotlin makes them much shorter, without sacrificing readability.

The init Block is Your Friend

In Java, the constructor is used for different operations:

  1. storing arguments into attributes
  2. passing arguments to the super constructor
  3. other initialization code

The first operation is a no-brainer because attributes are part of the class signature in Kotlin. Likewise, calling the super constructor is handled by the class signature. The rest of the initialization code is not part of the class signature and should be part of an init block. Most applications do not this part, but Vaadin needs to setup layout and related stuff.

class MainScreenPresenter(tablePresenter: TablePresenter,
                          buttonPresenter: NotificationButtonPresenter,
                          view: MainScreen, eventBus: EventBus) : Presenter<MainScreen>(view, eventBus) {

    init {
        view.setComponents(tablePresenter.view, buttonPresenter.view)
    }
}

Use the Apply Method

Kotlin has a standard library offering small dedicated functions. One of them is apply, defined as inline fun T.apply(f: T.() -> Unit): T (source). It’s an extension function, meaning every type will have it as soon as it’s imported into scope. This function requires an argument that is a function and that returns nothing. Inside this function, the object that has been apply-ed is accessible as this (and this is implicit, as in standard Java code). It allows code like this:

VerticalLayout(button, table).apply {
    setSpacing(true)
    setMargin(true)
    setSizeFull()
}

Factor View and Presenter into Same File

Kotlin makes code extremely small, thus some files might be only a line long (not counting import). Opening different files to check related classes is useless. Packages are a way to organize your code; I think files might be another way in Kotlin. For example, Vaadin views and presenters can be put into the same file.

class NotificationButton: Button("Click me")

class NotificationButtonPresenter(view: NotificationButton, eventBus: EventBus): Presenter<NotificationButton>(view, eventBus) { ... }

Lambdas Make Great Listeners

As of Java 8, single-method interfaces implemented as anonymous inner classes can be replaced with lambdas. Kotlin offers the same feature plus:

  • It allows to omit parentheses if the lambda is the only argument
  • If the lambda has a single argument, its default name is it and it doesn’t need to be declared

Both make for a very readable syntax when used in conjunction with the Vaadin API:

view.addValueChangeListener {
    val rowId = it.property.value
    val rowItem = view.containerDataSource.getItem(rowId)
    eventBus.publish(SESSION, rowItem)
}

Note: still, more complex logic should be put into its own function.

Spring Framework Spring Boot Kotlin (programming language) Vaadin

Published at DZone with permission of Nicolas Fränkel, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Be Punctual! Avoiding Kotlin’s lateinit In Spring Boot Testing
  • Improving Backend Performance Part 1/3: Lazy Loading in Vaadin Apps
  • Develop a Secure CRUD Application Using Angular and Spring Boot
  • Building Mancala Game in Microservices Using Spring Boot (Part 3: Web Client Microservice Implementation Using Vaadin)

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!