我们可以煮Java,Kotlin RestController吗?

几乎所有Java程序员在他的一生中都写过RestController,但是很少有人想知道他是否做得对。 即使您是一位经验丰富的程序员,您也可能会遇到我将要回答的问题。 本文将涵盖诸如1.5和2.0版本的Spring Boot框架以及quarkus(最近出现的Red Hat的Spring Boot竞争对手)的框架。

图片


问题


在Java和Spring Boot 1.5中编程了很长时间。 但是有必要编写一个新项目:

  1. 我有用于集成1600行的json,某些类具有100个字段
  2. 我想尝试Kotlin和Quarkus。
  3. 编写一个rest控制器,该控制器将能够与kotlin数据类一起使用,而无需使用注释并且无需涉及龙目岛魔术。 我希望数据类小

您可能猜到了kotlin数据类是一个不可变的类,或者说是不可变的。 一个类,其构造函数包含所有字段。 我非常相信这样的概念。 创建类后,无法更改;其中没有设置器。 由于无法在世界上更改Docker映像,因此属于控制器的date类是无法更改的。

让我们看一下解决问题的可能方法,更准确地说是在现代项目中如何编写控制器:

标准选项。 在弹簧或弹簧靴1.5上手动


Rest控制器是很久以前出现的,下面的示例是在所有教程中的Java中典型用法的示例。

我们只是创建最简单的控制器

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

并创建一个POJO(普通的旧Java对象)

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

私有字段和getters / setters或lombok批注可能会有变化,但要点不是。
太好了,我们创建了第一个可工作的rest控制器。 对于90%的情况,工作选项。 你可以留在这里。

问题:

不变的概念被打破了。
有点冗长的数据类。

我们可以使一成不变吗?


对这个问题的自然反应是决定删除默认构造函数并阻止编辑类字段。
 @Getter public class Fruit { private String name; private String description; // public Fruit() { // } public Fruit(String name, String description) { this.name = name; this.description = description; } } 

但是现在出现了一个问题,事实证明该库(很可能是杰克逊)无法创建该类。 您很可能会看到类似未找到默认构造函数的错误

因此,杰克逊首先使用不带参数的构造函数创建了该类,然后将其称为getter / setter 。 真是恐怖 毕竟,是否有一个带有所有参数的构造函数? 但是不幸的是,在编译类时,参数看起来像这样。

图片

在运行时,java对构造函数中的参数名称一无所知。 编译器会丢失它们。

第二个选项是spring或spring boot 1.5 +注释作为救赎


因此,我们意识到我们想要一个不变的类,并且我们知道我们正在使用杰克逊。 然后,厌倦症就来了。

 @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; } } 

目前,在我们关于sping boot 1.5的项目中,这些注释实际上包含了所有内容。
而且,如果您使用流行的jsonschema2pojo生成器,它将生成更多注释。 老实说,我不喜欢他们。

尝试在那里复制:

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

在输出中,我们得到(您可以斜视和翻阅):

 @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; } } 

缺点: 注释极大地增加了类。 非常冗长,对于业余爱好者而言。

第三选择弹簧或弹簧靴1.5 +龙目岛标志


谢谢Throwable我会在评论中引用:

“如果您使用Lombok,那么最好的方法是在lombok.config中编写:

lombok.allArgsConstructor.addConstructorProperties = true

这将在构造函数@java.beans.ConstructorProperties上生成,Jackson知道如何理解。”

很好的选择。 他一定会让我免于注释的冗长。

缺点:

但是我想不带龙目岛使用Kotlin。
我来不及学习此选项。

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; } } 

出乎意料的是,Spring Boot 2.0在这种不可变的类中可以安静地工作。 还有他的双胞胎兄弟Kotlin数据班

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

似乎Java在运行时中不知道构造函数中的参数名称,但是由于某种原因,spring boot2已经知道如何使用数据类。 因此,看看spring-boot-starter-parent,那里已经添加了Kotlin支持。

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

我解密。 为了使类构造函数中的参数名称在运行时不会丢失,编译器必须传递javac -parameters标志而spring boot 2.0 会这样做

弹簧靴2上的示例项目。

第五个选择。 夸库斯+科特林


Quarkus有一个休息服务的例子 ,这是我的首选。 即 休息控制器是老式的方法。 但是,如果要与Kotlin一起使用,则必须像Spring Boot 2一样添加标志。

问题描述在这里在此处为如何向quarkus添加kotlin数据类支持的示例。

结论


您可以使用第一个最简单的选项来创建rest控制器,但我建议您转向不可变的类。 在Kotlin上书写,您将不需要龙目岛。 代码应该越来越容易。 我确信spring的创建者会故意将javac -parameters添加到编译器选项中,并且这样做不会有任何犯罪。 祝大家在编写完美代码的过程中万事如意。

谢谢大家的关注!

Source: https://habr.com/ru/post/zh-CN480158/


All Articles