Skip to content

KotlinBeanInfoFactory.getBeanInfo throws exception when introspecting getter on value class #3109

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
vstepchik opened this issue Jun 17, 2024 · 4 comments
Assignees
Labels
type: bug A general bug

Comments

@vstepchik
Copy link

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

I think it is potentially similar to #2964 and #2990.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jun 17, 2024
@mp911de mp911de self-assigned this Jun 18, 2024
@mp911de mp911de added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged labels Jun 18, 2024
@mp911de
Copy link
Member

mp911de commented Jun 18, 2024

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.

@vstepchik
Copy link
Author

@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 added a commit that referenced this issue Jun 18, 2024
We now ignore Kotlin getters that are either static methods or would require additional arguments.

Closes #3109
mp911de added a commit that referenced this issue Jun 18, 2024
We now ignore Kotlin getters that are either static methods or would require additional arguments.

Closes #3109
@mp911de mp911de added this to the 3.2.8 (2023.1.8) milestone Jun 18, 2024
@vstepchik
Copy link
Author

@mp911de thank you for the fast response! 🥇

@mp911de
Copy link
Member

mp911de commented Jun 18, 2024

That's fixed now. If you want, you can give the most recent snapshots (available from repo.spring.io) a try.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug A general bug
Projects
None yet
Development

No branches or pull requests

3 participants