Spring-data 2.1使用Kotlin获得“ UnsupportedOperationException:没有访问者来设置属性”

时间:2019-01-20 06:51:47

标签: mongodb kotlin spring-data spring-data-mongodb

环境: Spring Boot 2.1.2.RELEASE, 弹簧数据2.1.4.RELEASE, Kotlin 1.2.x〜1.3.x, Mongodb。

我定义了一个模型类,例如:

@Document
class MeAccount : Setting() {

    lateinit var id: String

    val accountEntries = listOf<BankAccount>()
 }

当我尝试从mongodb读取此模型时,出现异常stacktrace打击:

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)

请注意,该代码与spring-boot 1.5.x和spring-data 1.x正常工作。

我该怎么做才能解决此问题? 似乎下面有许多类似的异常报告:

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

[已解决]在回退到Spring-boot 2.0.x和spring-data-commons 2.0.x之后工作。在将来的升级计划中将保留2.1。

2 个答案:

答案 0 :(得分:1)

2.1中的Spring数据。改变了处理实体中最终字段的方式。它不再使用反射来覆盖字段的不变性,这通常是好的。有几种方法可以解决该问题。

它们在这里描述:https://jira.spring.io/browse/DATACMNS-1374?focusedCommentId=182289&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-182289

这是春季队的建议:

  
      
  1. 添加@PersistenceConstructor来构建设置不可变字段的实体。
  2.   
  3. 添加凋谢方法(MyEntity withXxx(…))以创建一个包含更改后的属性值的新实例。
  4.   
  5. 或者:使用Kotlin的数据类功能。基本上,这和凋灵方法一样。
  6.   

因此,您应该像这样工作:

kubectl describe pods

答案 1 :(得分:0)

仅出于记录目的,因为我没有找到有关apache cassandra的弹簧数据的相同问题,文档建议仅使用@Value以避免DTO上@Data不变变化的样板,但是在该示例之后,spring抛出UnsupportedOperationException来解决此dto必须具有龙目岛实验 @Wither 才能工作。

存储库

<T> List<T> findByActive(Class<T> class);

DTO

@Value
public class PersonDTO {

    private UUID id;
    private Boolean active;
}

测试-致电

    List<PersonDTO> personList  = personService.findByActive(PersonDTO.class);

g

java.lang.UnsupportedOperationException: No accessor to set property private final java.lang.Boolean com.x.dto.PersonDTO.active!
    at com.x.dto.PersonDTO_Accessor_y82uew.setProperty(Unknown Source)
    at org.springframework.data.cassandra.repository.query.DtoInstantiatingConverter.lambda$convert$0(DtoInstantiatingConverter.java:107)
    at org.springframework.data.mapping.model.BasicPersistentEntity.doWithProperties(BasicPersistentEntity.java:369)
    at org.springframework.data.cassandra.repository.query.DtoInstantiatingConverter.convert(DtoInstantiatingConverter.java:101)
    at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.convert(ResultProcessor.java:224)
    at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.lambda$and$0(ResultProcessor.java:210)
    at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.convert(ResultProcessor.java:224)
    at org.springframework.data.repository.query.ResultProcessor.processResult(ResultProcessor.java:152)
    at org.springframework.data.cassandra.repository.query.CassandraQueryExecution$ResultProcessingConverter.convert(CassandraQueryExecution.java:267)
    at org.springframework.data.cassandra.repository.query.CassandraQueryExecution$ResultProcessingExecution.execute(CassandraQueryExecution.java:232)
    at org.springframework.data.cassandra.repository.query.AbstractCassandraQuery.execute(AbstractCassandraQuery.java:103)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:605)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
    at com.sun.proxy.$Proxy145.findByActive(Unknown Source)
    at com.x.service.impl.PersonServiceImpl.findByActive(PersonServiceImpl.java:22)
    at com.x.PersonRepositoryTest.findByActive(PersonRepositoryTest.java:78)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74)
    at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)

Spring Data for Apache Cassandra - Reference Documentation

  

避免为投影DTO设计样板代码   使用Project Lombok简化DTO的代码,该项目提供了   @Value注释(不要与Spring的@Value注释混淆   如前面的界面示例所示)。如果您使用龙目岛计划   @Value批注,前面显示的示例DTO将成为   以下:

@Value
@Wither //added - not included in documentation
class NamesOnly {
    String firstname, lastname;
}
  

动态投影到目前为止,我们已将投影类型用作   集合的返回类型或元素类型。但是,您可能想要   选择调用时要使用的类型(这使其成为   动态)。要应用动态投影,请使用查询方法,例如   在以下示例中显示了一个:

     

示例86.使用动态投影参数的存储库

interface PersonRepository extends Repository<Person, UUID> {

  <T> Collection<T> findByLastname(String lastname, Class<T> type);
}