Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring-data 2.1 get "UnsupportedOperationException: No accessor to set property" with kotlin

Environment: Spring-boot 2.1.2.RELEASE, Spring-data 2.1.4.RELEASE, Kotlin 1.2.x ~ 1.3.x, Mongodb.

I defined a model class like:

@Document
class MeAccount : Setting() {

    lateinit var id: String

    val accountEntries = listOf<BankAccount>()
 }

When I tried to read this model from mongodb, I got exception stacktrace blow:

java.lang.UnsupportedOperationException: No accessor to set property private final java.util.List com.xxx.MeCustodianAccount.accountEntries!
    at com.xxx.MeCustodianAccount_Accessor_fs514j.setProperty(Unknown Source)
    at org.springframework.data.mapping.model.ConvertingPropertyAccessor.setProperty(ConvertingPropertyAccessor.java:61)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.readProperties(MappingMongoConverter.java:378)

For attention, the code works fine with spring-boot 1.5.x and spring-data 1.x.

What can I do to solve this issue? Seems many similar exception reports below:

Spring boot 2.1.0 security change with kotlin data class?

https://github.com/arangodb/spring-data/issues/123

https://github.com/spring-projects/spring-boot/issues/15698

[Resolved] Works after fall back to Spring-boot 2.0.x and spring-data-commons 2.0.x. Will keep 2.1 excluded in future upgrading plans.

like image 416
Jack Zhu Avatar asked Jan 20 '19 06:01

Jack Zhu


1 Answers

Spring Data in 2.1. has changed the way in which it deals with final fields in entities. It no longer uses reflection to override the immutability of the fields, which in general is good. There are a few ways to cope with the problem.

They are described here: https://jira.spring.io/browse/DATACMNS-1374?focusedCommentId=182289&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-182289

Here's what the Spring guys recommend:

  1. Add a @PersistenceConstructor to construct the entity that sets immutable fields.
  2. Add wither methods (MyEntity withXxx(…)) to create a new instance that contains the changed property value.
  3. Alternatively: Use Kotlin's data class feature. This will basically do the same as wither methods.

So for you should work something like this:

@Document
data class MeAccount(val id: String, val accountEntries: List<Price>) : Setting()
like image 81
Michal Trojanowski Avatar answered Nov 16 '22 17:11

Michal Trojanowski