Home > database >  Spring Boot REST API - Type mismatch on field ID
Spring Boot REST API - Type mismatch on field ID

Time:09-24

I am new to Spring Boot with Kotlin and I am trying to implement a simple REST API with a MySQL database in the background. I started by creating a "TestEntity" class with a "TestEntityRepository", "TestEntityResource" and "TestEntityService". Everything worked fine until this point. I was able to POST and GET the data via the REST API.

After that I created another Entity "User" for which I wanted to do the same as for my TestEntity. I created the class with some more fields followed by the Repository, Resource and Service classes. Now, when I try to POST a new entry to my UserResource REST endpoint I get a 400 Bad Request error with the following message:

Field error in object 'user' on field 'id': rejected value [null]; codes [typeMismatch.user.id,typeMismatch.id,typeMismatch.long,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.id,id]; arguments []; default message [id]]; default message [Failed to convert value of type 'null' to required type 'long'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [null] to type [@javax.persistence.Id @javax.persistence.GeneratedValue long] for value 'null'; nested exception is java.lang.IllegalArgumentException: A null value cannot be assigned to a primitive type]]

My User class looks like the following:

@Entity
class User(
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    val id: Long,

    @Column(name = "login_id", unique = true, nullable = false)
    val loginId: String,

    @Column(name = "display_name")
    val displayName: String,

    @CreationTimestamp
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "created_date")
    val createdDate: Date,

    @UpdateTimestamp
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "modify_date")
    val modifyDate: Date
)

The repository class looks like this:

@Repository
interface UserRepository: JpaRepository<User, Long>

The service class like this:

@Service
class UserService(val repo: UserRepository) {

    fun findAll(): List<User> = repo.findAll()

    fun findById(userId: Long): User = repo.findById(userId)
        .orElseThrow { ResponseStatusException(HttpStatus.NOT_FOUND, "No user was found with this ID.") }

    fun post(user: User) {
        repo.save(user)
    }

    fun delete(user: User) {
        repo.delete(user)
    }
}

And finally my resource class (RestController) like this:

@RestController
class UserResource(val service: UserService) {

    @GetMapping("/user")
    fun get(): List<User> = service.findAll()

    @GetMapping("/user/{id}")
    fun get(@PathVariable(name = "id") id: Long): User = service.findById(id)

    @PostMapping("/user")
    fun post(user: User) {
        service.post(user)
    }

    @DeleteMapping("/user")
    fun delete(user: User) = service.delete(user)
}

Does anybody may have an idea what is going wrong? I am just sending a HTTP POST with a JSON object that contains the fields "loginId" and "displayName". The "id" field should be filled automatically but it does not work. Also when I add a field called "id" to my JSON the request will not be accepted.

Thanks!

CodePudding user response:

  1. Make sure auto_increement is set to id column in your table.
  2. Use Autogeneration Strategy as GenerationType.IDENTITY.

CodePudding user response:

Okay I found a way to fix it but I am not sure if its the best way to do.

In my entity class I had to declare the createdDate and modifyDate fields as nullable:

@Entity
class User(
    @Id
    @GeneratedValue
    var id: Long,

    @Column(name = "login_id", unique = true, nullable = false)
    var loginId: String,

    @GeneratedValue(generator = APITokenGenerator.GENERATOR_NAME)
    @GenericGenerator(name = APITokenGenerator.GENERATOR_NAME, strategy = "my.package.name.APITokenGenerator")
    @Column(name = "api_token")
    var apiToken: String? = null,

    @Column(name = "display_name")
    var displayName: String,

    @CreationTimestamp
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "created_date")
    var createdDate: Date? = null,

    @UpdateTimestamp
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "modify_date")
    var modifyDate: Date? = null
)

But I think the most important thing was to add the @RequestBody annotation to my RestController class which handles the incoming requests:

@RestController
@RequestMapping("/api/user")
class UserResource(val service: UserService) {

    @GetMapping()
    fun get(): List<User> = service.findAll()

    @GetMapping("/{id}")
    fun get(@PathVariable(name = "id") id: Long): User = service.findById(id)

    @PostMapping()
    fun post(@RequestBody user: User) {
        service.post(user)
    }

    @DeleteMapping("")
    fun delete(@RequestBody user: User) = service.delete(user)
}

It would be nice if someone can answer me if this is the correct solution or if there is something not correct anyway :-)

  • Related