【问题标题】:Problem to deserialize JSON class Kotlin with Spring Boot JPA使用 Spring Boot JPA 反序列化 JSON 类 Kotlin 的问题
【发布时间】:2021-05-16 15:33:00
【问题描述】:

我在使用 Spring Boot JPA 和 Kotlin 的 Rest API 时遇到问题。每次我尝试使用 POST 端点插入新记录时都会引发错误。

出现的错误日志:

JSON 解析错误:无法构造 com.lp3bmobi.paintcar_workshop_api.model.VehicleType 的实例(尽管至少存在一个 Creator):没有 int / Int-argument 构造函数/工厂方法可从 Number 值反序列化 (3)

VehicleType 类

@Entity
@Table(name="vehicle_types")
@EntityListeners(AuditingEntityListener::class)
@JsonDeserialize
data class VehicleType (
        @NotBlank
        @Column(name = "type_name")
        var typeName: String ?= null
        //@JsonProperty("typeName") var typeName: String ?= null
) {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    var id: Long ?= null
    //@JsonProperty("id") var id: Long = 0

    constructor(id: Long, typeName: String?): this(typeName) {
        this.id = id
    }

   //    @JsonCreator constructor(id: Long, typeName: String?): this(typeName) {
   //        this.id = id
   //    }

}

车辆类别

@Entity
@Table(name="vehicles")
@EntityListeners(AuditingEntityListener::class)
data class Vehicle (
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "id")
        var id: Long ?= null,

        @NotBlank
        @Column(name = "model_name")
        var modelName: String ?= null,

        @NotBlank
        @Column(name = "year")
        var year: Int ?= null,

        @NotBlank
        @Column(name = "brand_id")
        var brand: Int ?= null,

        @NotBlank
        @Column(name = "description")
        var description: String ?= null,

        @NotBlank
        @Column(name = "approved")
        var approved: Boolean ?= null,

        @OneToOne(fetch = FetchType.LAZY) //cascade = arrayOf(CascadeType.ALL)
        @JoinColumn(name = "vehicle_type_id", referencedColumnName = "id")
        var vehicleType: VehicleType,
        //@JsonProperty("vehicleType") var vehicleType: VehicleType ?= null,
)

车辆控制器

@PostMapping("/vehicle/new")
fun createVehicle(@RequestBody vehicle: Vehicle): ResponseEntity<Vehicle?>? { //EntityModel<Vehicle>
        try {
          val _vehicle: Vehicle = vehicleRepository
                  //.save(Vehicle(vehicle.content))
                 //.save(Vehicle(0, vehicle.modelName, vehicle.year, vehicle.brand,
                //              vehicle.description, false, vehicle.vehicleType))
                .save(vehicle)
           return ResponseEntity<Vehicle?>(_vehicle, HttpStatus.CREATED)
       } catch (e: java.lang.Exception) {
           return ResponseEntity<Vehicle?>(null, HttpStatus.INTERNAL_SERVER_ERROR)
    }
}

【问题讨论】:

  • 作为一种风格,String ?= null 等令人困惑! Kotlin 没有 ?= 运算符。我花了好一会儿才弄清楚这只是String? = null,即一个可为空字符串类型的参数,默认为空。令人惊讶的是,即使编译器不在乎,间距对人类的影响也有多大……
  • 删除构造函数。它需要一个零 arg 构造函数,它使用反射将 json 转换为对象来填充该构造函数。当您将值设置为默认值时,就像您通过将它们设置为 null 一样,您实际上在 koltin 中获得了 n+1 个构造函数。如果有的话,您可能需要创建一个零参数构造函数。此外,作为旁注,创建不是实体的单独请求或响应类是最佳实践(随意不同意),因此您明确决定接收/发送哪些字段。例如:通过获取一个 id 并使用 JPAs 保存方法很容易覆盖其他人的数据

标签: java spring spring-boot kotlin


【解决方案1】:

错误消息似乎是说 Spring 找不到 VehicleType 的构造函数,采用单个 Int 参数,所以显而易见的是给它一个!

您可以通过添加另一个辅助构造函数来做到这一点:

constructor(id: Int): this(null) {
    this.id = id.toLong()
}

(免责声明:我自己没有尝试过……如果有效,请告诉我们!)

如果现有的辅助参数采用 Int 而不是 Long,那么另一种选择是为其其他参数提供默认值。 (在这种情况下,您还需要添加 @JvmOverloads 注释,以确保它在字节码中生成额外的构造函数。)

我不确定为什么当属性定义为 Long 时它会尝试使用 Int;也许这与referencedColumnName = "id" 列有关?无论如何,Kotlin 在 Long 和 Ints(以及其他数字类型)之间的区别方面比 Java 或 C 等语言更严格一些。

【讨论】:

  • 即使按照您的建议,同样的错误仍然存​​在,添加带有参数 int 的辅助构造函数
猜你喜欢
  • 2018-02-05
  • 2020-02-22
  • 2017-10-30
  • 2018-07-24
  • 2018-09-25
  • 2016-12-31
  • 1970-01-01
  • 2020-10-17
  • 1970-01-01
相关资源
最近更新 更多