spring 数据休息 kotlin 协会 POST
spring data rest kotlin associations POST
我遵循了教程 http://www.baeldung.com/spring-data-rest-relationships。
我还观察到我可以通过向关系提供 link 来直接创建关联。
curl -i -X POST -H "Content-Type:application/json" -d '{"name":"My Library"}' http://localhost:8080/libraries
curl -i -X POST -d '{"title":"Books", "library":"http://localhost:8080/libraries/1"}' -H "Content-Type:application/json" http://localhost:8080/books
这在 Java 中工作正常,在使用常规 class 时在 Kotlin 中也能正常工作。
但是,如果我在 Kotlin 中使用数据 class,我会收到以下错误
2018-04-26 14:13:43.730 ERROR 79256 --- [nio-8080-exec-2] b.e.h.RestResponseEntityExceptionHandler : org.springframework.http.converter.HttpMessageNotReadableException: JSON 解析错误: 无法构造 com.baeldung.models.Library 的实例(尽管至少存在一个创建者):没有字符串参数 constructor/factory 方法从 [Source: (org.apache.catalina.connector.CoyoteInputStream);行:1,列:29](通过引用链:com.baeldung.models.Book["library"])
我的项目中确实有相关的 kotlin-spring、kotlin-jpa 和 kotlin-noarg 插件。
Kotlin 数据 classes 非常严格。它告诉您,基本上,它无法构建您的 POKO,并且列出了它尝试的一些方法。其中之一是使用 String 构造函数。其他是通过私有字段操作(这是通常完成的方式)。
Kotlin 中的数据 classes,如果它们的字段声明为 private val name:String
转换为(在 java 中)private final String name;
它不能分配给 final
字段(尝试分配给私有字段是脏的,但当它是最终的时是不可能的;JVM 不允许它)并且没有 getName()
或 setName()
函数可以是用作另一种补水方法。
部分选项:
- 声明你的变量是
var
而不是 val
。 private var name:String
java 等同于 private String name
将使用基于现场的(肮脏的)水合作用。
- 为 kotlin 添加一个特定的 kotlin 依赖项来解决这个问题:
compile("com.fasterxml.jackson.module:jackson-module-kotlin")
看看 this project
应该适合您的 kotlin 示例 class:
import org.springframework.hateoas.Identifiable
import java.time.LocalDate
import javax.persistence.*
import javax.validation.constraints.*
@Entity
data class Employee(@Pattern(regexp = "[A-Za-z0-9]+")
@Size(min = 6, max = 32)
val name: String,
@Email
@NotNull
val email: String?,
@PastOrPresent
val hireDate: LocalDate = LocalDate.now(),
@OneToMany(mappedBy = "employee", cascade = [CascadeType.ALL])
val forms:List<Form> = listOf(),
@OneToMany(mappedBy = "employee", cascade = [CascadeType.ALL])
val reports:List<Report> = listOf(),
@Id @GeneratedValue( strategy = GenerationType.IDENTITY) private val id: Long? = null): Identifiable<Long> {
override fun getId() = id
constructor(name:String): this(name,"$name@foo.com")
}
有了kotlin就OK了。
只需将"data class"替换为"class"即可。
Jackson 在 "data class" 中没有找到空构造函数。并使用其他反序列化器...而不是 Uri....
尝试在主构造函数上添加 @JsonCreator(mode = JsonCreator.Mode.DISABLED)
注释。无需禁用 com.fasterxml.jackson.module:jackson-module-kotlin
.
解释:
- Kotlin Jackson 模块暗示您的默认构造函数是 JSON 创建者(参见
KotlinValueInstantiator
class)。
- 因此,Spring Data REST 不应用其 bean 反序列化器修饰符(应该通过 URI 加载 bean),因为 bean 属性映射不用于创建者属性(构造函数参数)。
- KotlinValueInstantiator 尝试使用标准反序列化器和实例化器反序列化构造函数参数,这会导致您提到的错误。
可能的解决方案:
由于 koltin-jpa 模块为 JPA 添加了一个默认的空构造函数,您可以通过显式禁用它来指示 Jackson 不要使用 JSON 创建者,而是使用默认的空构造函数。
示例:
@Entity
class Book @JsonCreator(mode = JsonCreator.Mode.DISABLED) constructor(
@ManyToMany
val libraries: ModifiableList<Library> = ArrayList(),
): AbstractPersistable<Long>(), Identifiable<Long>
我遵循了教程 http://www.baeldung.com/spring-data-rest-relationships。 我还观察到我可以通过向关系提供 link 来直接创建关联。
curl -i -X POST -H "Content-Type:application/json" -d '{"name":"My Library"}' http://localhost:8080/libraries
curl -i -X POST -d '{"title":"Books", "library":"http://localhost:8080/libraries/1"}' -H "Content-Type:application/json" http://localhost:8080/books
这在 Java 中工作正常,在使用常规 class 时在 Kotlin 中也能正常工作。
但是,如果我在 Kotlin 中使用数据 class,我会收到以下错误
2018-04-26 14:13:43.730 ERROR 79256 --- [nio-8080-exec-2] b.e.h.RestResponseEntityExceptionHandler : org.springframework.http.converter.HttpMessageNotReadableException: JSON 解析错误: 无法构造 com.baeldung.models.Library 的实例(尽管至少存在一个创建者):没有字符串参数 constructor/factory 方法从 [Source: (org.apache.catalina.connector.CoyoteInputStream);行:1,列:29](通过引用链:com.baeldung.models.Book["library"])
我的项目中确实有相关的 kotlin-spring、kotlin-jpa 和 kotlin-noarg 插件。
Kotlin 数据 classes 非常严格。它告诉您,基本上,它无法构建您的 POKO,并且列出了它尝试的一些方法。其中之一是使用 String 构造函数。其他是通过私有字段操作(这是通常完成的方式)。
Kotlin 中的数据 classes,如果它们的字段声明为 private val name:String
转换为(在 java 中)private final String name;
它不能分配给 final
字段(尝试分配给私有字段是脏的,但当它是最终的时是不可能的;JVM 不允许它)并且没有 getName()
或 setName()
函数可以是用作另一种补水方法。
部分选项:
- 声明你的变量是
var
而不是val
。private var name:String
java 等同于private String name
将使用基于现场的(肮脏的)水合作用。 - 为 kotlin 添加一个特定的 kotlin 依赖项来解决这个问题:
compile("com.fasterxml.jackson.module:jackson-module-kotlin")
看看 this project
应该适合您的 kotlin 示例 class:
import org.springframework.hateoas.Identifiable
import java.time.LocalDate
import javax.persistence.*
import javax.validation.constraints.*
@Entity
data class Employee(@Pattern(regexp = "[A-Za-z0-9]+")
@Size(min = 6, max = 32)
val name: String,
@Email
@NotNull
val email: String?,
@PastOrPresent
val hireDate: LocalDate = LocalDate.now(),
@OneToMany(mappedBy = "employee", cascade = [CascadeType.ALL])
val forms:List<Form> = listOf(),
@OneToMany(mappedBy = "employee", cascade = [CascadeType.ALL])
val reports:List<Report> = listOf(),
@Id @GeneratedValue( strategy = GenerationType.IDENTITY) private val id: Long? = null): Identifiable<Long> {
override fun getId() = id
constructor(name:String): this(name,"$name@foo.com")
}
有了kotlin就OK了。
只需将"data class"替换为"class"即可。
Jackson 在 "data class" 中没有找到空构造函数。并使用其他反序列化器...而不是 Uri....
尝试在主构造函数上添加 @JsonCreator(mode = JsonCreator.Mode.DISABLED)
注释。无需禁用 com.fasterxml.jackson.module:jackson-module-kotlin
.
解释:
- Kotlin Jackson 模块暗示您的默认构造函数是 JSON 创建者(参见
KotlinValueInstantiator
class)。 - 因此,Spring Data REST 不应用其 bean 反序列化器修饰符(应该通过 URI 加载 bean),因为 bean 属性映射不用于创建者属性(构造函数参数)。
- KotlinValueInstantiator 尝试使用标准反序列化器和实例化器反序列化构造函数参数,这会导致您提到的错误。
可能的解决方案:
由于 koltin-jpa 模块为 JPA 添加了一个默认的空构造函数,您可以通过显式禁用它来指示 Jackson 不要使用 JSON 创建者,而是使用默认的空构造函数。
示例:
@Entity
class Book @JsonCreator(mode = JsonCreator.Mode.DISABLED) constructor(
@ManyToMany
val libraries: ModifiableList<Library> = ArrayList(),
): AbstractPersistable<Long>(), Identifiable<Long>