春季数据休息kotlin协会POST

时间:2018-04-27 20:42:52

标签: kotlin spring-data spring-data-jpa spring-data-rest jackson-databind

我按照教程http://www.baeldung.com/spring-data-rest-relationships进行了操作。 我还观察到我可以通过提供关系链接直接创建关联。

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和Kotlin中都可以正常工作。

但是,如果我在Kotlin中使用数据类,则会出现以下错误

2018-04-26 14:13:43.730 ERROR 79256 --- [nio-8080-exec-2] behRestResponseEntityExceptionHandler:org.springframework.http.converter.HttpMessageNotReadableException:JSON解析错误:无法构造com的实例。 baeldung.models.Library(尽管至少存在一个Creator):没有String-argument构造函数/工厂方法从String值反序列化('http://localhost:8080/libraries/1');嵌套异常是com.fasterxml.jackson.databind.exc.MismatchedInputException:无法构造com.baeldung.models.Library的实例(尽管至少存在一个Creator):没有String-argument构造函数/工厂方法从String值反序列化(' http://localhost:8080/libraries/1')在[来源:(org.apache.catalina.connector.CoyoteInputStream); line:1,column:29](通过引用链:com.baeldung.models.Book [“library”])

我的项目中有相关的kotlin-spring,kotlin-jpa和kotlin-noarg插件。

代码在这里https://github.com/vijaysl/spring-data-rest

3 个答案:

答案 0 :(得分:2)

尝试在主要构造函数上添加@JsonCreator(mode = JsonCreator.Mode.DISABLED)批注。无需禁用com.fasterxml.jackson.module:jackson-module-kotlin

说明:

  • Kotlin Jackson模块意味着您的默认构造函数是JSON创建者(请参见KotlinValueInstantiator类)。
  • 因此,Spring Bean 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>

答案 1 :(得分:0)

Kotlin数据类非常严格。它告诉你,基本上,它不能构建你的POKO,它列出了它尝试的一些方法。其中一个是String构造函数。其他人则通过私人现场操纵(这是它正常运作的方式)。

kotlin中的数据类,如果它们具有声明为private val name:String的字段,则转换为(在java中)private final String name;它不能分配给final字段(这是很脏的尝试分配到私有字段,但是当它是最终的时候是不可能的; JVM不会允许它,并且没有getName()setName()函数可以用作另一个水合方法。

一些选项:

  1. 声明您的变量为var而不是valprivate var name:String是与private String name等价的java,它将使用基于字段的(脏)水合作用。
  2. 包含针对kotlin的特定kotlin依赖项,可解决此问题:compile("com.fasterxml.jackson.module:jackson-module-kotlin")查看this project
  3. 示例kotlin类应该适合您:

    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")
    }
    

答案 2 :(得分:0)

与科特琳都很好。

只需将“数据类”替换为“类”。

Jackson在“数据类”中找不到空的构造函数。并使用其他反序列化器...而不是Uri ...