这个问题使我身体不适。
开个玩笑,我一直在尝试使用带有安全性插件的spring-boot向我的Web应用程序添加身份验证层。这是我的数据类。
@Document(collection = "user")
data class User (
var name : String,
var password : String,
var email : String,
var type : String,
var status : String,
var balance : Int
){
@Id val id : String = ObjectId.get().toHexString()
}
在进行Ctr + C,Ctr + V搜索之后,我成功设置了一些自定义身份验证,该身份验证将从数据库中获取用户信息,如下所示:
override fun loadUserByUsername(name : String): UserDetails {
logger.info(name)
val user = repo.findByName(name)
return User(user!!.name,passwordEncoder.encode(user.password),AuthorityUtils.NO_AUTHORITIES)
}
从这里开始有趣,似乎代码从未运行过val user = repo.findByName(name)
。最糟糕的是,没有异常被抛出,代码运行到该行,其余代码消失了。
出于沮丧,我决定伪造返回对象,以便可以通过这样的身份验证:
override fun loadUserByUsername(name : String): UserDetails {
logger.info(name)
//val user = repo.findByName(name)
logger.debug("asdkfhasdklfjhasdf")
return User("string",passwordEncoder.encode("you"),AuthorityUtils.NO_AUTHORITIES)
}
现在,终于可以得到一些例外了:
{
"timestamp": "2018-11-08T18:08:29.541+0000",
"status": 500,
"error": "Internal Server Error",
"message": "No accessor to set property @org.springframework.data.annotation.Id()private final java.lang.String com.sonnbh.jwt.User.id!",
"path": "/user"
}
spring无法访问属性id
的异常状态,因此我将id
的类型从val
更改为var
。
@Document(collection = "user")
data class User (
var name : String,
var password : String,
var email : String,
var type : String,
var status : String,
var balance : Int
){
@Id var id : String = ObjectId.get().toHexString()
}
最后,我的应用程序按预期工作。但是,在尝试更深入地研究问题之后,我发现此问题仅发生在spring-boot v2.1.0
上。我使用spring-boot v2.0.5
的旧项目实际上在val id
上运行良好。这使我提出了一个问题:
User
的旧实现是否正确?我只想防止从数据库或init读取对User.id
的任何更改。我该怎么做才能改善?spring-boot v2.1
无法像spring-boot v2.0.5
那样访问属性?答案 0 :(得分:0)
只能回答第一部分;您可以尝试将ID声明移到构造函数之外?这样可以满足您仅在创建对象时进行初始化的要求,并且该对象仍然是只读的。
答案 1 :(得分:0)
2.1中的Spring数据。改变了处理实体中最终字段的方式。它不再使用反射来覆盖字段的不变性,这通常是好的。有几种方法可以解决该问题。
这是春季队的建议:
- 添加@PersistenceConstructor来构建设置不可变字段的实体。
- 添加凋谢方法(MyEntity withXxx(…))以创建一个包含更改后的属性值的新实例。
- 或者:使用Kotlin的数据类功能。基本上,这和凋灵方法一样。