指定为非空的参数为空:无法更新 Spring Boot jpa 中的单个实体字段。导致指定为非空的参数为空
Posted
技术标签:
【中文标题】指定为非空的参数为空:无法更新 Spring Boot jpa 中的单个实体字段。导致指定为非空的参数为空【英文标题】:Parameter specified as non-null is null:Can't Update individual Entity field in Spring Boot jpa. Caused Parameter specified as non-null is null 【发布时间】:2021-06-01 00:06:30 【问题描述】:最近,我正在学习使用 Postgrasql 作为数据库的 Spring Boot。我所有的 POST、GET、DELETE 方法都可以在没有 PUT 方法的情况下完美运行。我想要的是更新实体的单个字段。但是如果我不更新所有字段,它会说“指定为非空的参数为空”
我的代码是
User.kt
import java.time.LocalDate
import javax.persistence.*
import javax.persistence.GenerationType.SEQUENCE
@Entity
@Table(name = "user_info")
data class User(
@Id
@SequenceGenerator(
name = "user_seq",
sequenceName = "user_seq",
allocationSize = 1
)
@GeneratedValue(
strategy = SEQUENCE,
generator = "user_seq"
)
@Column(
name = "id",
updatable = false
)
val id: Long = -1,
@Column(
name = "first_name",
nullable = false,
length = 50,
updatable = true
)
val firstName: String,
@Column(
name = "last_name",
nullable = false,
length = 50,
updatable = true
)
val lastName: String,
@Column(
name = "email",
nullable = true,
length = 150,
updatable = true
)
val email: String,
@Column(
name = "gender",
nullable = false,
length = 2,
updatable = true
)
val gender: String,
@Column(
name = "date_of_birth",
nullable = false,
updatable = true
)
val dateOfBirth: LocalDate,
@Column(
name = "country",
nullable = false,
length = 50,
updatable = true
)
val country: String
)
UserController.kt
包 com.example.demo.user
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.format.annotation.DateTimeFormat
import org.springframework.format.annotation.DateTimeFormat.ISO.DATE
import org.springframework.web.bind.annotation.*
import java.time.LocalDate
@RestController
@RequestMapping(
path = [
"/api/v1/"
]
)
class UserController(
@Autowired private val userService: UserService
)
@PutMapping("update/id")
fun updateUser(
@PathVariable("id") id: Long,
@RequestParam(required = false) firstName: String,
@RequestParam(required = false) lastName: String,
@RequestParam(required = false) email: String,
@RequestParam(required = false) gender: String,
@RequestParam(required = false) country: String,
@RequestParam(required = false) @DateTimeFormat(iso = DATE) dateOfBirth: LocalDate
)
return userService.updateUser(id, firstName, lastName, email, gender, country, dateOfBirth)
UserService.kt
package com.example.demo.user
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.time.LocalDate
@Service
class UserService(
@Autowired private val userRepository: UserRepository
)
fun registerUser(user: User)
if (userRepository.findUserByEmail(user.email).isPresent) throw IllegalStateException("Email Already taken")
userRepository.save(user)
fun getUsers(offset: Int): List<User>
return userRepository.getUsers(offset)
fun getUserInfo(userId: Long): User
if (!userRepository.existsById(userId)) throw IllegalArgumentException("User not found")
return userRepository.findById(userId).get()
fun deleteUser(userId: Long)
if (!userRepository.existsById(userId)) throw IllegalStateException("User with id $userId does not exist")
userRepository.deleteById(userId)
@Transactional
fun updateUser(id: Long, firstName: String, lastName: String, email: String, gender: String, country: String, dateOfBirth: LocalDate)
val user = userRepository.findById(id).orElseThrow throw IllegalStateException("User with id $id does not exist")
// if (userRepository.findUserByEmail(user.email).isPresent) throw IllegalStateException("Email Already taken")
if (firstName.isNotEmpty()) user.firstName = firstName
if (lastName.isNotEmpty()) user.lastName = lastName
if (email.isNotEmpty()) user.email = email
if (gender.isNotEmpty() && (gender == "M" || gender == "F")) user.gender = gender
if (country.isNotEmpty()) user.country = country
if (dateOfBirth.toString().isNotEmpty()) user.dateOfBirth = dateOfBirth
响应负载是
"timestamp": "2021-03-02T11:45:27.025+00:00",
"status": 500,
"error": "Internal Server Error",
"message": "Parameter specified as non-null is null: method com.example.demo.user.UserController.updateUser, parameter dateOfBirth",
"path": "/api/v1/update/1000"
【问题讨论】:
可以添加用户服务代码吗? @AnthonyChatellier 添加了。请检查 【参考方案1】:问题来自您的 REST 控制器。请求参数使用 required=false 注释,但类型为 String。因此,当 HTTP 请求带有空值时,Spring 无法反序列化这些字段中的数据。 (这解释了 NullpointerException。
您必须在您的控制器中提供可空类型(如“字符串?”),并且这种可空性不应该在代码的所有层中激增。
例如,“名字”对于更新是可选的,但对于创建是必需的。
【讨论】:
感谢您的回复。在我的控制器类中添加可空类型后,我得到了“内部服务器错误”【参考方案2】:我在 kotlin 上工作不多,但我认为问题在于 Kotlin 是 null-safe 编程语言。您需要明确告知变量是否可以为空。有关更多详细信息,请参阅此blog。使用接受 null 的字段更新您的实体类应该可以工作。
例如要允许空值,可以将变量声明为可空字符串,写成String?:
【讨论】:
感谢您的回复。在我的控制器类中添加可空类型后,我得到了“内部服务器错误” 为控制器和实体添加可空性以上是关于指定为非空的参数为空:无法更新 Spring Boot jpa 中的单个实体字段。导致指定为非空的参数为空的主要内容,如果未能解决你的问题,请参考以下文章
java.lang.IllegalArgumentException:指定为非空的参数为空:方法 kotlin.jvm.internal.Intrinsics.checkParameterIsNotN
Graphiql 中标记为非空的所有字段和参数:Sangria,scala
SpringBoot 接收Get请求个别参数可能为空的解决方案
java.security.InvalidAlgorithmParameterException:Linux上的trustAnchors参数必须为非空,或者为啥默认的信任库为空[重复]