用Kotlin数据类替换Java DTO类的问题

时间:2018-06-25 09:56:32

标签: java kotlin dto

我阅读了有关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作为依赖项的工件时,出现了这样的异常:

  

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

正如我看到的那样,Jackson无法将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类?

2 个答案:

答案 0 :(得分:7)

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

jackson-module-kotlin

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

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

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

答案 1 :(得分:2)

就我而言,我在Java中创建了kotlin类DTO实例以使用RESTful Api。 现在,我测试了2个解决方案:

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

reference科特林说:

  

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

所以我在科特林有一个这样的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());
...