将 Java DTO 类替换为 Kotlin 数据类时出现问题



我读过 Kotlin 数据类,并认为它们在描述数据传输对象 (DTO( 的情况下非常有用。在我的Java项目中,我已经有了用Java编写的DTO类,如下所示:

public class Tweet {
private String id;
private String profileId;
private String message;
public Tweet() {}
public String getId() {
return id;
}
public String getProfileId() {
return profileId;
}
public String getMessage() {
return message;
}
public void setId(String id) {
this.id = id;
}
public void setProfileId(String profileId) {
this.profileId = profileId;
}
public Tweet setMessage(String message) {
this.message = message;
return this;
}
}

这些 DTO 类存储在单独的工件中,我将其作为依赖项添加到其他工件中。所以,我决定用 Kotlin 类替换它,并在 Kotlin 上重写了提到的 Tweet 类,所以它开始看起来像:

data class Tweet(var id: String? = null,
var profileId: String? = null,
var message: String? = null)

这是我第一次使用 Kotlin,所以可能有一些东西看起来很丑陋,但我的主要问题是 - 当我尝试重建使用我的 DTO 作为依赖项的工件时,我得到这样的异常:

at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2992( at io.vertx.core.json.Json.decodeValue(Json.java:117( at gk.tweetsched.api.repository.TweetRepository.get(TweetRepository.java:51( at gk.tweetsched.api.repository.TweetRepositoryTest.testGet(TweetRepositoryTest.java:68( 原因:java.lang.ClassNotFoundException: kotlin.jvm.internal.DefaultConstructorMarker at java.net.URLClassLoader.findClass(URLClassLoader.java:381( at java.lang.ClassLoader.loadClass(ClassLoader.java:424( at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335( at java.lang.ClassLoader.loadClass(ClassLoader.java:357( ...67 更多

正如我所看到的,根据堆栈跟踪,杰克逊无法将 JSON 反序列化为 Tweet Kotlin 类。

这是我的 Java 方法,我得到这个异常:

public Tweet get(String id) {
try (Jedis jedis = pool.getResource()) {
return Json.decodeValue(jedis.hget(TWEETS_HASH, id), Tweet.class);
} catch (Exception e) {
LOGGER.error(e);
}
return null;
}

其中 Json 类来自 'io.vertx.core.json' 包。

如何解决此问题?我应该在我的 Java 项目中进行哪些额外的配置来使用 Kotlin 类?

默认情况下,Jackson 需要一个无参数构造函数来将 JSON 反序列化为类 - Kotlin 数据类没有,因此您需要添加一个 Jackson 模块来处理此问题:

杰克逊-模块-科特林

编辑: 我已经阅读了io.vertx.core.json.Json类的源代码,似乎该类使用的两个对象映射器都存储在公共静态字段中。

因此,要注册 jackson-module-kotlin,您需要在应用程序初始化代码中包含此代码片段(或者其他任何地方,只要在尝试反序列化任何 Kotlin 数据类之前执行它(:

Json.mapper.registerModule(new KotlinModule())
Json.prettyMapper.registerModule(new KotlinModule()) 

就我而言,我在java中创建kotlin类DTO实例来消费RESTful API。 现在我测试了 2 个解决方案:

  1. 在数据类中使用无参数构造函数。

参考 kotlin 说:

在 JVM 上,如果主构造函数的所有参数都有 默认值,编译器将生成一个额外的无参数 将使用默认值的构造函数。这使得更容易 将 Kotlin 与创建类的库(如 Jackson 或 JPA(一起使用 通过无参数构造函数的实例。

所以我在 kotlin 中有一个 DTO,如下所示:

data class Dto (
var id: Int?=null,
var version: Int?=null, 
var title: String?=null,
var firstname: String?=null,
var lastname: String?=null,
var birthdate: String?=null
)

然后,我在 java 中创建类实例 DTO:

Dto dto = new Dto();
dto.setId(javadto.getId());
...
  1. 使用插件 jackson-module-kotlin

import com.fasterxml.jackson.annotation.JsonProperty

data class Dto (
@JsonProperty("id") var id: Int?,
@JsonProperty("version") var version: Int?, 
@JsonProperty("title") var title: String?,
@JsonProperty("firstname") var firstname: String?,
@JsonProperty("lastname") var lastname: String?,
@JsonProperty("birthdate") var birthdate: String?,
)

然后,我在 java 中创建类实例 DTO:

Dto dto = new Dto(null, null, null, null, null, null);
dto.setId(javadto.getId());
...

最新更新