Spring Boot und Kotlin

1. Übersicht

Bereits im Januar wurde im Spring-Ökosystem eine große Ankündigung gemacht: Kotlin-Unterstützung kommt zu Spring Framework 5 . Dies bedeutet, dass Spring Boot 2.x erstklassige Unterstützung für Kotlin bietet.

Dies ist natürlich nicht unerwartet, da das Team von Pivotal für die Akzeptanz von JVM-Sprachen wie Scala und Groovy bekannt ist.

Erstellen wir eine Kotlin-App mit der Spring Boot-App 2.x!

2. Setup

2.1. Umgebung

Kotlin unterstützt die Entwicklung in IntelliJ, Eclipse und in der Befehlszeile. Befolgen Sie die Anweisungen, um Ihre Umgebung basierend auf Ihren Einstellungen einzurichten.

2.2. Konfiguration

Lassen Sie uns zunächst ein Spring Boot 2-Projekt erstellen und das POM so ändern, dass es Einträge enthält, die die Versionen von Java und Kotlin mit den Abhängigkeiten angeben:

 org.jetbrains.kotlin kotlin-stdlib-jre8 1.2.71   org.jetbrains.kotlin kotlin-reflect 1.2.71   com.fasterxml.jackson.module jackson-module-kotlin 2.9.9 

Beachten Sie, dass wir Dateispeicherorte für unsere Kotlin-Quell- und Testdateien angeben:

${project.basedir}/src/main/kotlin ${project.basedir}/src/test/kotlin

Wenn sich unsere Kotlin-Dateien an verschiedenen Orten befinden, müssen Sie diese Einträge im POM ändern.

Um Kotlin-Module und -Quellen zu kompilieren, müssen wir das Kotlin-Maven-Plugin verwenden:

 kotlin-maven-plugin org.jetbrains.kotlin 1.1.2   spring  1.8    compile compile  compile    test-compile test-compile  test-compile      org.jetbrains.kotlin kotlin-maven-allopen 1.1.2   

Okay, jetzt haben wir alles, was wir brauchen, um unsere Kotlin-Anwendung zu erstellen. Als Referenz: Sie finden die neuesten Versionen von Maven Central (Spring-Boot-Starter-Web, Kotlin-Stdlib-Jre8, Kotlin-Reflect, Jackson-Modul-Kotlin, Test).

Als nächstes richten wir unseren Anwendungskontext ein.

3. Anwendungskontext

Lassen Sie uns in einen Kotlin-Code springen und unseren bekannten Spring Boot-Anwendungskontext schreiben:

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

Wir sehen unsere bekannte @ SpringBootApplication- Annotation. Dies ist die gleiche Anmerkung, die wir in einer Java-Klasse verwenden würden.

Darunter haben wir eine Klassendefinition für unsere KotlinDemoApplication- Klasse. In Kotlin ist der Standardbereich für Klassen öffentlich, sodass wir dies weglassen können. Wenn eine Klasse keine Variablen und keine Funktionen hat, kann sie außerdem ohne geschweifte Klammern deklariert werden. Im Wesentlichen haben wir gerade eine Klasse definiert.

Fahren Sie mit der Methode fort. Dies ist die Standardmethode für den Java-Einstiegspunkt in Java: public static void main (String [] args).

Auch hier sind Methoden oder Funktionen standardmäßig öffentlich, sodass wir dies hier nicht deklarieren müssen. Darüber hinaus müssen Funktionen, die nichts zurückgeben, keinen ungültigen Rückgabetyp angeben.

Und schließlich ist jede außerhalb des Körpers einer Klasse definierte Funktion automatisch statisch . Dadurch ist diese Funktion für die Startausführung geeignet.

Führen Sie nun unsere Anwendung mit mvn spring-boot: run aus dem Stammverzeichnis aus . Die Anwendung sollte gestartet werden und unsere Anwendung sollte auf Port 8080 ausgeführt werden.

Als nächstes bauen wir einen Controller.

4. Controller

Werfen wir einen Blick auf das Hinzufügen eines Controllers zu unserem Service:

@RestController class HelloController { @GetMapping("/hello") fun helloKotlin(): String { return "hello world" } }

Nicht zu viel anders als ein Standard-Federregler, aber sicherlich weniger Code. Fügen wir eine Testklasse und einen Fall für diesen Controller hinzu, um unsere Arbeit zu validieren:

@RunWith(SpringRunner::class) @SpringBootTest(classes = arrayOf(KotlinDemoApplication::class), webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class KotlinDemoApplicationTests { @Autowired lateinit var testRestTemplate: TestRestTemplate @Test fun whenCalled_shouldReturnHello() { val result = testRestTemplate // ... .getForEntity("/hello", String::class.java) assertNotNull(result) assertEquals(result?.statusCode, HttpStatus.OK) assertEquals(result?.body, "hello world") } }

Dieser Test zeigt eine der sehr leistungsstarken Funktionen von Kotlin - Null Sicherheit! Kotlin-Variablen, die null sein können, müssen mit '?' Deklariert werden. Der Compiler weiß dann, dass eine defensive Codierung erforderlich ist, bevor auf diese Eigenschaft zugegriffen werden kann.

In unserem Test wird TestRestTemplate als nullbarer Typ definiert. Jedes Mal, wenn wir darauf zugreifen, verwenden wir den Null-Koaleszenzoperator "?". - was null zurückgibt, wenn das aufgerufene Objekt null ist.

Dies verdeutlicht die Verwendung von Nullen im Programm und zwingt Entwickler, bei der Arbeit mit ihnen sicheren Code zu schreiben.

Als nächstes fügen wir einen Service hinzu und integrieren diesen in unseren Controller.

5. Service

Wie Sie jetzt wahrscheinlich erraten können, wird es ziemlich einfach sein, unseren Service in unser Projekt aufzunehmen. Machen wir das jetzt:

@Service class HelloService { fun getHello(): String { return "hello service" } }

Ziemlich einfacher Service hier mit einer einzigen Funktion, die einen String zurückgibt. Als nächstes verbinden wir unseren Service mit dem Controller und geben damit einen Wert zurück:

@RestController class HelloController(val helloService: HelloService) { // ... @GetMapping("/hello-service") fun helloKotlinService(): String { return helloService.getHello() } }

Ahh, das sieht gut aus! In Kotlin kann der Hauptkonstruktor in Übereinstimmung mit der Klassendeklaration definiert werden. Wir haben die Annotation @Autowired in unserem Konstruktor weggelassen, da sie seit einiger Zeit nicht mehr obligatorisch ist.

Diese Parameter werden automatisch in Felder in der Klasse konvertiert. Kotlin nennt man Eigenschaften. Es sind keine Getter oder Setter definiert. Sie werden automatisch erstellt. Sie können diese Standardeinstellungen natürlich überschreiben, wenn Sie möchten.

In Kotlin, properties in classes and variables in functions can be defined using var or val. Var indicates a mutable property, and val indicates a final one. This allows the compiler to check for illegal access. Since our HelloService is a singleton, we wire it up as a val to prevent mutation.

Next, let's add a test for this controller method:

@Test fun whenCalled_shouldReturnHelloService() { var result = testRestTemplate // ... .getForEntity("/hello-service", String::class.java) assertNotNull(result) assertEquals(result?.statusCode, HttpStatus.OK) assertEquals(result?.body, "hello service") }

Lastly, let's look at what a POJO looks like in Kotlin.

6. Kotlin Data Class

In Java, we represent data objects with plain old Java objects, the POJO. In Kotlin we have something that lets us express this type of object more concisely – a data class.

Let's write a data object to return in our controller:

data class HelloDto(val greeting: String)

That was no trick. I'm not omitting anything from our class. With the data modifier, we get a lot of benefits. This keyword automatically creates an equals/hashcode pair, a toString function, and a copy function. All that from a 53 character one-liner!

Now let's add a method to return our new data class:

// ... @GetMapping("/hello-dto") fun helloDto(): HelloDto { return HelloDto("Hello from the dto") }

The data modifier does not add a default constructor, which is important for certain libraries like Jackson. To support this type of class we have added the jackson-module-kotlin to our POM file to support marshaling. This was done during section 2, and you can see the dependency there.

Finally, let's add a test for this controller function:

@Test fun whenCalled_shoudlReturnJSON() { val result = testRestTemplate // ... .getForEntity("/hello-dto", HelloDto::class.java) assertNotNull(result) assertEquals(result?.statusCode, HttpStatus.OK) assertEquals(result?.body, HelloDto("Hello from the dto")) }

7. Conclusion

In diesem Artikel haben wir uns mit der Kotlin-Unterstützung in Spring Boot 2.x befasst. Wir haben anhand von Beispielen gesehen, dass Kotlin unsere Anwendungen vereinfachen und verbessern kann, indem er uns zwingt, kürzeren, sichereren Code zu schreiben.

Kotlin unterstützt auch einige erstaunliche Funktionen wie die Datenklasse, Klassenerweiterungen und ist vollständig kompatibel mit vorhandenem Java-Code. Dies bedeutet, dass Sie Kotlin-Code schreiben und von Ihren Java-Klassen aus aufrufen können und umgekehrt. Darüber hinaus wurde Kotlin von Grund auf neu entwickelt, um eine fantastische Unterstützung in einer IDE zu bieten.

Es gibt viele Gründe, Kotlin auszuprobieren, und da Google und Spring es unterstützen, ist es jetzt an der Zeit, es auszuprobieren. Lassen Sie uns wissen, was Sie beschlossen haben, damit zu bauen!

Den Quellcode finden Sie immer auf GitHub.