`KotlinBeanInfoFactory.getBeanInfo` throws exception when introspecting getter on value class
vstepchik opened this issue · comments
Hi!
When upgrading from spring-data-commons 3.0.1 to 3.3.1 (also to 3.2.0, but on 3.1.0 works fine) the following code throws exception:
@JvmInline
value class Foo(val value: String) {
val foo: String get() = "foo-$value"
}
// ...
val foo = org.springframework.beans.BeanUtils.getPropertyDescriptors(Foo::class.java)
The exception:
Failed to obtain BeanInfo for class [com.redacted.MyTest$Foo]
org.springframework.beans.FatalBeanException: Failed to obtain BeanInfo for class [com.redacted.MyTest$Foo]
at app//org.springframework.beans.CachedIntrospectionResults.<init>(CachedIntrospectionResults.java:301)
at app//org.springframework.beans.CachedIntrospectionResults.forClass(CachedIntrospectionResults.java:157)
at app//org.springframework.beans.BeanUtils.getPropertyDescriptors(BeanUtils.java:488)
at app//com.redacted.MyTest.<clinit>(AuditDaoTest.kt:44)
at java.base@17.0.1/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base@17.0.1/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
at java.base@17.0.1/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.base@17.0.1/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
at java.base@17.0.1/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
at app//org.junit.platform.commons.util.ReflectionUtils.newInstance(ReflectionUtils.java:553)
at app//org.junit.jupiter.engine.execution.ConstructorInvocation.proceed(ConstructorInvocation.java:56)
at app//org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
at app//org.junit.jupiter.api.extension.InvocationInterceptor.interceptTestClassConstructor(InvocationInterceptor.java:74)
at app//org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93)
at app//org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
at app//org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
at app//org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
at app//org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
at app//org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92)
at app//org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:62)
at app//org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeTestClassConstructor(ClassBasedTestDescriptor.java:364)
at app//org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateTestClass(ClassBasedTestDescriptor.java:311)
at app//org.junit.jupiter.engine.descriptor.ClassTestDescriptor.instantiateTestClass(ClassTestDescriptor.java:79)
at app//org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateAndPostProcessTestInstance(ClassBasedTestDescriptor.java:287)
at app//org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$4(ClassBasedTestDescriptor.java:279)
at java.base@17.0.1/java.util.Optional.orElseGet(Optional.java:364)
at app//org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$5(ClassBasedTestDescriptor.java:278)
at app//org.junit.jupiter.engine.execution.TestInstancesProvider.getTestInstances(TestInstancesProvider.java:31)
at app//org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$prepare$0(TestMethodTestDescriptor.java:106)
at app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at app//org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:105)
at app//org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:69)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$prepare$2(NodeTestTask.java:123)
at app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.prepare(NodeTestTask.java:123)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:90)
at app//org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService$ExclusiveTask.compute(ForkJoinPoolHierarchicalTestExecutorService.java:202)
at app//org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService.executeNonConcurrentTasks(ForkJoinPoolHierarchicalTestExecutorService.java:172)
at app//org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService.invokeAll(ForkJoinPoolHierarchicalTestExecutorService.java:152)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
at app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at app//org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at app//org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService$ExclusiveTask.compute(ForkJoinPoolHierarchicalTestExecutorService.java:202)
at app//org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService.invokeAll(ForkJoinPoolHierarchicalTestExecutorService.java:146)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
at app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at app//org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at app//org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService$ExclusiveTask.compute(ForkJoinPoolHierarchicalTestExecutorService.java:202)
at java.base@17.0.1/java.util.concurrent.RecursiveAction.exec(RecursiveAction.java:194)
at java.base@17.0.1/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
at java.base@17.0.1/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
at java.base@17.0.1/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
at java.base@17.0.1/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
at java.base@17.0.1/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)
Caused by: java.beans.IntrospectionException: bad read method arg count: public static final java.lang.String com.redacted.MyTest$Foo.getFoo-impl(java.lang.String)
at java.desktop/java.beans.PropertyDescriptor.findPropertyType(PropertyDescriptor.java:684)
at java.desktop/java.beans.PropertyDescriptor.setReadMethod(PropertyDescriptor.java:281)
at java.desktop/java.beans.PropertyDescriptor.<init>(PropertyDescriptor.java:141)
at org.springframework.data.util.KotlinBeanInfoFactory.getBeanInfo(KotlinBeanInfoFactory.java:78)
at org.springframework.beans.CachedIntrospectionResults.getBeanInfo(CachedIntrospectionResults.java:222)
at org.springframework.beans.CachedIntrospectionResults.<init>(CachedIntrospectionResults.java:248)
... 63 more
Thanks for reaching out. While the exception is a bug, I'm not entirely sure about the overall handling of inline class properties.
I'm leaning towards ignoring inline class properties as they do not adhere to the Java Beans design where getters do not accept any arguments except for by-index (for arrays or collections) access. Furthermore, the getters Kotlin generates (get…-impl(…)
) are static methods.
So, we would consider only the inline class component as an actual property.
Paging @sdeleuze for further thoughts.
@mp911de I agree with this, as for serialization purposes value classes should be perceived as primitive types or strings, and thus not serialized as complex objects with nested properties.
@mp911de thank you for the fast response! 🥇
That's fixed now. If you want, you can give the most recent snapshots (available from repo.spring.io) a try.