Pouvons-nous cuisiner Java, Kotlin RestController?

Presque n'importe quel programmeur java a écrit RestController dans sa vie, mais peu de gens se demandent s'il le fait correctement. Même si vous êtes un programmeur expérimenté, vous aurez peut-être des questions auxquelles j'essaierai de répondre. L'article couvrira des cadres tels que les versions 1.5 et 2.0 de Spring Boot, ainsi que Quarkus, le rival récemment apparu de Spring Boot de Red Hat.

image


Le problème


Programmé depuis longtemps en Java et Spring Boot 1.5. Mais il fallait écrire un nouveau projet:

  1. J'ai json pour intégrer 1600 lignes, certaines classes ont 100 champs
  2. Je voulais essayer Kotlin et Quarkus.
  3. Écrivez un contrôleur de repos qui pourrait fonctionner avec la classe de données kotlin sans annotations et sans impliquer la magie lombok. Je veux que la classe de données soit petite

Vous avez probablement deviné que la classe de données kotlin est une classe immuable, ou immuable. Une classe dont le constructeur contient tous les champs. Je suis un grand partisan d'un tel concept; après avoir créé une classe, elle ne peut pas être modifiée, il n'y a pas de setters dedans. Comme l'image docker ne peut pas être modifiée dans le monde, la classe de date qui est tombée dans le contrôleur est quelque chose qui ne peut pas être modifiée.

Examinons les moyens possibles de résoudre le problème, plus précisément comment, dans les projets modernes, vous pouvez écrire un contrôleur:

L'option standard. manuellement sur ressort ou sur ressort 1.5


Les contrôleurs de repos sont apparus il y a longtemps et l'exemple suivant est un exemple typique de leur utilisation en java, qui se trouve dans tous les didacticiels.

Nous créons simplement le contrôleur le plus simple

@RestController public class FruitController { @PostMapping("/fruit") public void greeting(@RequestBody Fruit request) { System.out.println(request); } } 

Et créer un POJO (simple vieil objet java)

 public class Fruit { public String name; public String description; public Fruit() { } public Fruit(String name, String description) { this.name = name; this.description = description; } } 

il peut y avoir des variations avec des champs privés et des getters / setters ou des annotations lombok, mais pas le point.
Génial, nous avons créé le premier contrôleur de repos qui fonctionne. Pour 90% des cas, l'option de travail. Tu peux rester ici.

Les problèmes:

Le concept immuable est rompu.
Une classe de données peu verbeuse.

Pouvons-nous rendre immuable?


Une réaction naturelle à ce problème sera la décision de supprimer le constructeur par défaut et d'empêcher la modification des champs de classe.
 @Getter public class Fruit { private String name; private String description; // public Fruit() { // } public Fruit(String name, String description) { this.name = name; this.description = description; } } 

Mais maintenant un problème se pose, il s'avère que la bibliothèque (probablement jackson) ne peut pas créer la classe. Vous verrez probablement une erreur comme Aucun constructeur par défaut trouvé.

Donc, jackson a d'abord créé la classe en utilisant le constructeur sans paramètres, puis appelé getter / setter . Quelle horreur. Après tout, existe-t-il un constructeur avec tous les paramètres? Mais malheureusement, lorsque la classe est compilée, les paramètres ressemblent à ceci.

image

C'est-à-dire au moment de l'exécution, java ne sait rien des noms de paramètres dans le constructeur. Le compilateur les perd.

La deuxième option est le ressort ou la botte de ressort 1.5 + annotations comme salut


Nous avons donc réalisé que nous voulions une classe immuable et nous savons que nous utilisons jackson. Puis une anatotation vient à la rescousse.

 @Getter public class Fruit { private String name; private String description; @JsonCreator public Fruit(@JsonProperty("name") String name, @JsonProperty("description")String description) { this.name = name; this.description = description; } } 

Pour le moment, dans notre projet sur sping boot 1.5, ces annotations sont littéralement pleines de tout.
Et si vous prenez le générateur jsonschema2pojo populaire, il générera encore plus d'annotations. Honnêtement, je ne les aime pas.

Essayez de copier là-bas:

 { "description": "description", "name": "name" } 

À la sortie, nous obtenons (vous pouvez plisser les yeux et feuilleter):

 @JsonInclude(JsonInclude.Include.NON_NULL) @JsonPropertyOrder({ "description", "name" }) public class Example { @JsonProperty("description") private String description; @JsonProperty("name") private String name; @JsonProperty("description") public String getDescription() { return description; } @JsonProperty("description") public void setDescription(String description) { this.description = description; } @JsonProperty("name") public String getName() { return name; } @JsonProperty("name") public void setName(String name) { this.name = name; } } 

Inconvénients: les annotations gonflent considérablement la classe. Très verbeux, pour un amateur.

Troisième option ressort ou botte de ressort 1.5 + drapeau lombok


Merci Throwable je citerai du commentaire:

"Si vous utilisez Lombok, alors la meilleure façon est d'écrire dans lombok.config:

lombok.allArgsConstructor.addConstructorProperties = true

Cela générera sur le constructeur @java.beans.ConstructorProperties , que Jackson sait comprendre. »

Excellente option. Il me sauverait sûrement de la verbosité des annotations.

Inconvénients:

Mais je veux utiliser Kotlin sans lombok.
J'ai appris cette option trop tard.

La quatrième version de Spring boot 2.0


 @Getter public class Fruit { private String name; private String description; public Fruit( String name, String description) { this.name = name; this.description = description; } } 

Étonnamment, Spring Boot 2.0 fonctionne silencieusement avec une classe aussi immuable. Et aussi avec son frère jumeau kotlin data class

 data class Fruit( val name : String, val description : String) 

Il semblerait que java en runtime ne connaisse pas les noms des paramètres dans le constructeur, mais pour une raison quelconque, spring boot2 sait déjà comment travailler avec la classe de données. Alors, regardez Spring-boot-starter-parent, le support Kotlin a été ajouté là-bas.

 <plugin> <groupId>org.jetbrains.kotlin</groupId> ... <configuration> <javaParameters>true</javaParameters> </configuration> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <parameters>true</parameters> </configuration> </plugin> 

Je déchiffre. Pour que les noms de paramètres dans le constructeur de classe ne soient pas perdus pendant l'exécution, le compilateur doit passer l' indicateur javac -parameters Et Spring Boot 2.0 le fait.

Exemple de projet sur la botte de printemps 2 .

La cinquième option. Quarkus + Kotlin


Quarkus a un exemple de service de repos , un analogue de ma première option. C'est-à-dire contrôleur de repos à l'ancienne. Cependant, si vous souhaitez l'utiliser avec Kotlin, vous devrez ajouter des indicateurs comme l'a fait Spring Boot 2.

Description du problème ici . Un exemple de la façon d'ajouter le support de classe de données kotlin à quarkus ici .

Conclusions


Vous pouvez utiliser la première option la plus simple pour créer des contrôleurs de repos, mais je conseillerais de passer à des classes immuables. Écrivez sur Kotlin et vous n'aurez pas besoin de lombok. Le code devrait être de plus en plus facile. Je suis sûr que les créateurs de Spring sont délibérément allés ajouter des paramètres javac aux options du compilateur et il ne devrait y avoir aucun crime à ce sujet. Bonne chance à tous sur le chemin du code parfait.

Merci à tous pour votre attention!

Source: https://habr.com/ru/post/fr480158/


All Articles