杰克逊·杰森(Jackson Json)

时间:2020-03-12 19:19:29

标签: java json spring kotlin jackson

我正在将Java Spring应用程序重写为Kotlin Spring应用程序。

除了对openweather的API请求外,其他所有方法都可以正常工作。

要将DTO存储在数据库中,有一个id字段以及从API检索到的cityId(在那里称为id)。

由于某些原因,@ JsonIgnore不适用于DTO id字段。

build.gradle

// plugins

    id 'org.springframework.boot' version '2.2.4.RELEASE'
    id 'io.spring.dependency-management' version '1.0.9.RELEASE'
    id 'java'
    id 'war'
    id 'maven'
    id 'org.jetbrains.kotlin.jvm' version '1.3.70'
    id "org.jetbrains.kotlin.plugin.jpa" version "1.3.70"
    id "org.jetbrains.kotlin.plugin.noarg" version "1.3.70"
    id "org.jetbrains.kotlin.plugin.spring" version "1.3.70"
    id "org.jetbrains.kotlin.plugin.allopen" version "1.3.70"


// dependencies

    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.boot:spring-boot-starter-mail:2.2.4.RELEASE'
    implementation 'org.springframework.security:spring-security-test'
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
    implementation "org.jetbrains.kotlin:kotlin-reflect"
    implementation "com.fasterxml.jackson.module:jackson-module-kotlin:2.10.2"

OpenWeather使用下一个JSON响应(某些字段省略):

{
    "coord":{
        "lon":-0.13,
        "lat":51.51
    },
    "main":{
        "temp":14.04,
        "feels_like":7.05,
        "pressure":1011,
        "humidity":61
    },
    "dt":1584018901,
    "id":2643743,              <- cityId in DTO class
    "name":"London",
 ...
}

DTO类:


import com.fasterxml.jackson.annotation.JsonIgnore
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import com.fasterxml.jackson.annotation.JsonProperty

@JsonIgnoreProperties(ignoreUnknown = true)
data class OpenWeatherApiDto(
        @JsonIgnore
        override var id: Long? = null,
        ...
        override var cityId: Int? = null,
        ...
) : AbstractWeatherSampleDto() {
    ...
    @JsonProperty("id")
    private fun unpackId(idObj: Int?) {
        cityId = idObj
                ?: throw ApiFieldNotFoundException("id")
    }
    ...
}

测试失败

@Test
    fun createFromFile() {
        val mapper = jacksonObjectMapper()
        Files.lines(Paths.get("src/test/resources/data/OWApi.json")).use { s ->
            val json: String = s.collect(Collectors.joining())
            val ws: OpenWeatherApiDto = mapper.readValue(json)
            println(ws)
            assertThat(ws)
                    .isNotNull
                    .extracting("cityId").isEqualTo(2643743)
        }
    }

失败消息是:

[Extracted: cityId] 
Expecting:
 <null>
to be equal to:
 <2643743>
but was not.

实际对象是:

OpenWeatherApiDto( id = 2643743 ,cityName = London,温度= 14.04,feelsLike = 7.05,压力= 1011.0,湿度= 61,云层=空, cityId = null ,时间= 1584018901,纬度= 51.51,经度= -0.13)

我在jackson-module-kotlin GitHub page上发现了类似的问题,在 2.9.6 jackson-databind relatedresolved >当我使用 2.10.2

2 个答案:

答案 0 :(得分:2)

我还没有尝试使用您使用的确切版本,但是如果您将@JsonIgnore替换为@get:JsonIgnore ,我怀疑它会起作用。

这是将Java转换为Kotlin时常见的陷阱之一。在Java中,通常使用私有字段和getter方法(以及可变的setter)来实现属性。您可能还包括一个构造函数参数以对其进行初始化。最多需要四个单独的代码位,所有这些位都与同一个属性相关,并且每个位可以有自己的注释。

但是,在Kotlin中,您可以从一小段代码中获得所有这些代码。 (任何非私有属性都会为您提供一个私有字段和一个getter方法;如果它是var,那么您还将获得一个setter;如果它在主构造函数中,那么您还将获得一个构造函数参数。)这更加简洁!

但是任何注释适用于什么?

默认情况下,它们适用于构造函数param,或者,如果属性在类主体中定义,则属性本身(仅对Kotlin可见)。因此,如果您希望他们将其应用于字段,getter或setter,则需要明确指定,例如@field:JsonIgnore@get:JsonIgnore

详细信息在Kotlin docs中。

答案 1 :(得分:0)

我没有找到解决方案,但是

    @JsonProperty("_id")
    override var id: Long? = null,

它按预期工作。

相关问题