具有单值 JSON 的简单 SpringBoot 服务失败

Simple SpringBoot service with single value JSONs fail

提问人:szedjani 提问时间:11/16/2023 更新时间:11/20/2023 访问量:29

问:

我在 kotlin (1.9.10) Spring Boot (3.1.5) 应用程序中有以下 RestController。

package io.company.connectors.fauxservice.actions

import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RestController

@RestController
class EchoAction {

    data class EchoActionOutput(
        val content: String,
    )

    data class EchoActionInput(
        val text: String,
    )

    data class EchoActionRequestBody(
        val inputs: EchoActionInput,
    )

    @PostMapping("/fauxservice/actions/echo/execute")
    fun execute(@RequestBody body: EchoActionRequestBody): EchoActionOutput {
        return EchoActionOutput(body.inputs.text)
    }
}

我尝试使用以下 POST 请求到达终点:

{
    "inputs": {
      "text": "banana"
    }
}

我期待这样的回应:{"content": "banana"}

但是,我得到这个(状态内部服务器错误):500

org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class io.company.connectors.fauxservice.actions.EchoAction$EchoActionRequestBody]...

我发现,如果我向输入对象添加额外的可选参数,那么它就会按预期工作:

    data class EchoActionInput(
        val text: String,
        val empty: String?,
    )

    data class EchoActionRequestBody(
        val inputs: EchoActionInput,
        val empty: String?,
    )

如果我只调整 EchoActionRequestBody,则会收到以下错误(状态为错误请求):400

org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of `io.company.connectors.fauxservice.actions.EchoAction$EchoActionInput` (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator)...

我做错了什么?创建单值数据类的正确方法是什么?

Spring Spring-Boot Rest Kotlin

评论

0赞 P.J.Meisch 11/17/2023
你的设置中一定有一些东西。我在 Kotlin 中使用 Web 依赖项从 Spring Initializr 创建了一个新项目,添加了您的类,它的工作方式应有尽有。引导 3.1.5 和 Kotlin 1.9.10。
0赞 szedjani 11/17/2023
@P.J.Meisch,谢谢,这个错误不会发生在一个简单的项目中。我有一个包含多个服务的两层项目。下面是一个重现错误的简化项目:github.com/szedjani/springdemo

答:

0赞 PaulNUK 11/20/2023 #1

Jackson 的工作原理是调用默认构造函数,然后逐个设置每个属性;如果你有一个不可为空的字段,你不会得到一个默认的构造函数,然后你会得到问题。

查看您的 gradle 构建脚本,它们与 Spring Initialiser (https://start.spring.io) 生成的标准脚本有很大不同。你最好用它作为模板来生成你的项目,因为 Spring 将配置你使用普通数据类所需的所有插件,如你的代码所示。从本质上讲,您可能缺少一些 Jackson 配置或特定于 kotlin 的 Jackson 插件,这些插件是由初始值设定器生成的普通 Spring Boot 应用程序免费提供给您的。

例如,至少你需要 jackson-module-kotlin 作为依赖项,并配置默认的 Spring Boot 对象映射器来注册它,这是 Spring Boot 启动器会为你做的事情。

评论

0赞 szedjani 11/21/2023
我修改了生成的项目,因为我必须创建多个子模块。这(github.com/szedjani/springdemo)只是项目的简化版本,只是为了重现问题。您是否有更多信息说明为什么我没有带有单个不可空字段的默认构造函数,但是如果我有两个不可空字段,我会得到一个?不过,生成的项目也没有将 jackson-module-kotlin 列为依赖项。