Spring Boot et Kotlin

1. Vue d'ensemble

Une grande annonce a été faite en janvier dans l'écosystème Spring: le support Kotlin arrive dans Spring Framework 5 . Cela signifie que Spring Boot 2.x aura un support de première classe pour Kotlin.

Ce n'est bien sûr pas inattendu, car l'équipe de Pivotal est connue pour l'acceptation des langages JVM tels que Scala et Groovy.

Créons une application Kotlin à l'aide de l'application Spring Boot 2.x!

2. Configuration

2.1. Environnement

Kotlin prend en charge le développement dans IntelliJ, Eclipse et sur la ligne de commande. Suivez les instructions pour configurer votre environnement, en fonction de vos préférences.

2.2. Installer

Tout d'abord, créons un projet Spring Boot 2 et modifions le POM pour qu'il contienne des entrées spécifiant les versions de Java et Kotlin avec les dépendances:

 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 

Notez que nous spécifions des emplacements de fichiers pour nos fichiers source et de test Kotlin:

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

Si nos fichiers Kotlin se trouvent à des emplacements différents, vous devrez modifier ces entrées dans le POM.

Pour compiler les modules et les sources Kotlin, nous devons utiliser kotlin-maven-plugin:

 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   

D'accord, nous avons maintenant tout ce dont nous avons besoin pour créer notre application Kotlin. Pour référence: vous pouvez trouver les dernières versions de Maven Central (spring-boot-starter-web, kotlin-stdlib-jre8, kotlin-reflect, jackson-module-kotlin, test).

Ensuite, configurons notre contexte d'application.

3. Contexte de l'application

Passons au code Kotlin et écrivons notre contexte d'application Spring Boot familier:

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

Nous voyons notre annotation familière @SpringBootApplication . C'est la même annotation que nous utiliserions dans une classe Java.

Ci-dessous, nous avons une définition de classe pour notre classe KotlinDemoApplication . Dans Kotlin, la portée par défaut des classes est publique afin que nous puissions l'omettre. De plus, si une classe n'a ni variable ni fonction, elle peut être déclarée sans accolades. Donc, en substance, nous venons de définir une classe.

Passons à la méthode. Il s'agit de la méthode standard du point d'entrée Java, en Java: public static void main (String [] args).

Encore une fois, les méthodes ou fonctions sont publiques par défaut, nous n'avons donc pas à le déclarer ici. De plus, les fonctions qui ne renvoient rien n'ont pas besoin de spécifier un type de retour void.

Et enfin, toute fonction définie en dehors du corps d'une classe est automatiquement statique . Cela rend cette fonction éligible pour l'exécution au démarrage.

Maintenant, exécutons notre application à partir du répertoire racine en utilisant mvn spring-boot: run . L'application devrait démarrer et nous devrions voir notre application s'exécuter sur le port 8080.

Ensuite, construisons un contrôleur.

4. Contrôleur

Jetons un coup d'œil à l'ajout d'un contrôleur à notre service:

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

Pas trop différent d'un contrôleur Spring standard mais certainement moins de code. Ajoutons une classe de test et un cas pour ce contrôleur afin de valider notre travail:

@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") } }

Ce test montre l'une des fonctionnalités très puissantes de Kotlin: la sécurité nulle! Les variables Kotlin qui peuvent être nulles doivent être déclarées en utilisant '?'. Le compilateur sait alors qu'un codage défensif est nécessaire avant d'accéder à cette propriété.

Dans notre test, TestRestTemplate est défini comme un type Nullable, et chaque fois que nous y accédons , nous le faisons à l'aide de l'opérateur de fusion nul «?». - qui renverra null si l'objet appelé est nul.

Cela clarifie l'utilisation des valeurs nulles dans le programme et oblige les développeurs à écrire du code sécurisé lorsqu'ils travaillent avec eux.

Ensuite, ajoutons un service et intégrons-le dans notre contrôleur.

5. Service

Comme vous pouvez probablement le deviner maintenant, notre service sera assez facile à ajouter à notre projet. Faisons cela maintenant:

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

Service assez simple ici avec une seule fonction renvoyant une chaîne. Ensuite, connectons notre service au contrôleur et utilisons-le pour renvoyer une valeur:

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

Ahh, ça a l'air sympa! Dans Kotlin, le constructeur principal peut être défini en ligne avec la déclaration de classe. Nous avons omis l' annotation @Autowired de notre constructeur car elle n'est plus obligatoire depuis un certain temps.

Ces paramètres sont automatiquement convertis en champs de la classe. Kotlin ils sont appelés propriétés. Il n'y a pas de getters ou de setters définis; ils sont créés automatiquement. Vous pouvez, bien entendu, remplacer ces valeurs par défaut si vous le souhaitez.

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

Dans cet article, nous avons examiné le support Kotlin dans Spring Boot 2.x. Nous avons vu à partir d'exemples que Kotlin pouvait simplifier et améliorer nos applications en nous obligeant à écrire du code plus court et plus sûr.

Kotlin prend également en charge certaines fonctionnalités étonnantes telles que la classe de données, les extensions de classe et est entièrement compatible avec le code Java existant. Cela signifie que vous pouvez écrire du code Kotlin et l'appeler à partir de vos classes Java et vice-versa. De plus, Kotlin a été conçu dès le départ pour bénéficier d'un support fantastique dans un IDE, et c'est le cas.

Il y a de nombreuses raisons d'essayer Kotlin, et avec le soutien de Google et de Spring, il est maintenant temps de le vérifier. Faites-nous savoir ce que vous avez décidé de construire en l'utilisant!

Toujours, vous pouvez trouver le code source sur GitHub.