【发布时间】:2021-08-06 04:49:15
【问题描述】:
我跟随 this tutorial 使用 Spring Boot 在 Kotlin 中创建了一个基本的 Web 应用程序。但是,我无法发布与现有资源具有多对一关系的新实体。
我的代码:
@Entity
class Song(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Long? = null,
var title: String,
@ManyToOne(fetch = FetchType.EAGER)
var addedBy: User)
@Entity
class User(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Long? = null,
var email: String,
var displayName: String)
@RestController
@RequestMapping("/api/songs")
class SongController(private val repository: SongRepository) {
@PostMapping("/")
fun add(@RequestBody song: Song) =
repository.save(song)
This answer 和其他人指出您可以使用其 URI 引用另一个资源,但发送以下请求:
{
"title": "Some title",
"addedBy": "http://localhost:8080/api/users/1"
}
给我一个堆栈跟踪错误org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of 'com.example.springboot.User' (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('http://localhost:8080/api/users/1'); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of 'com.example.springboot.User' (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('http://localhost:8080/api/users/1')\n at [Source: (PushbackInputStream); line: 6, column: 13] (through reference chain: com.example.springboot.Song[\"addedBy\"])
我发现在 Jackson/Hibernate/Spring Data 之间的某个地方,它无法将 User 资源 URI 转换为 User 实体,但我不知道应该在哪里发生这种魔法。
这似乎是 Kotlin 特有的问题。这里关于 SO 的所有建议都不能解决这个特定的错误,并且教程本身就没有处理关系。如果以这种方式处理关系根本不是正确的方法,我很想知道首选的做法是什么。
【问题讨论】:
-
您究竟将什么作为正文发布到端点?异常已经告诉你出了什么问题。 Song 对象(例如 addedBy 属性)不能仅基于提供的字符串反序列化。您至少需要用户的子对象 json 表示此外,您不应直接将实体发布到控制器。使用值对象,然后将它们映射到实体。所以你需要创建一个 Song 的实例。根据add by,你需要获取对应的用户实体,并将该实体添加到歌曲中。您也可以只提供用户 ID,然后提供映射。
-
@Daniel 我正在发送如上所述的请求正文(第三个代码块)还是您的意思是别的?直接发送实体而不必使用值对象正是 Spring 教程所做的,并且通过使用资源 URI 引用其他实体应该可以与 Spring 一起使用 OOB,对吗?另请参阅他们在这里做了什么,但使用 PUT 代替 baeldung.com/spring-data-rest-relationships
-
嘿 Steven,本教程使用 HATEOAS。使用
"books" : { "href" : "http://localhost:8080/authors/1/books" }查看他们引用相应子实体的请求正文,这意味着您还应该将此模式应用于您的请求。否则这将不起作用。 HATEOAS 允许您通过相应的资源路径直接引用相关的子实体,但您需要保留您发布的请求正文缺少的必要结构。 -
谢谢@DanielWosch,我似乎一直在挑选我在问题中提到的那些实际上使用Spring Data REST(我不是)的例子,我想这就是我的混乱来自。 Spring Data REST 似乎确实遵循 HATEOAS,我将尝试在我的项目中使用它。再次感谢!
-
我已经为您的问题发布了相应的答案,因此您可以接受它;)
标签: spring-boot kotlin spring-data-jpa