Problem to deserialize JSON class Kotlin with Spring Boot JPA

Viewed 496

I'm having a problem with a Rest API with Spring Boot JPA and Kotlin. An error is thrown every time I try to insert a new record using the POST endpoint.

The error log that appears:

JSON parse error: Cannot construct instance of com.lp3bmobi.paintcar_workshop_api.model.VehicleType (although at least one Creator exists): no int / Int-argument constructor / factory method to deserialize from Number value (3)

VehicleType Class

@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
   //    }

}

Vehicle Class

@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,
)

VehicleController

@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)
    }
}
1 Answers

The error message seems to be saying that Spring can't find a constructor for VehicleType taking a single Int argument, so the obvious thing is to give it one!

You could do that by adding another secondary constructor:

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

(Disclaimer: I haven't tried it myself…  Please let us know if it works!)

If the existing secondary parameter took an Int instead of a Long, then another option would be to give a default value for its other parameter.  (In that case you'd also need to add a @JvmOverloads annotation, to ensure that it generates the additional constructor in the bytecode.)

I'm not sure why it's trying to use an Int when the property is defined as a Long; maybe it's to do with the referencedColumnName = "id" column?  In any case, Kotlin is a bit stricter than languages like Java or C about the difference between Longs and Ints (and other numeric types).

Related