-
Notifications
You must be signed in to change notification settings - Fork 677
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
Add support for Kotlin Value Classes #2866
Conversation
Reflection-based instantiation is still a TODO
Also, refactor common code into kotlin instantiation metadata utility.
Switch to older ticket number.
* @see JvmClassMappingKt | ||
* @see ReflectJvmMapping | ||
*/ | ||
public class KotlinBeanInfoFactory implements BeanInfoFactory, Ordered { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sdeleuze what's your take on moving this one to core framework?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have in my todo to have a broader look to value class support in Framework, I will share my feedback on this specific point after and comment here.
I wonder if more of the underlying Kotlin class analysis code should / would need to move to Spring Framework, so that the standard framework binding subsystem was enabled to populate these types as well? |
This commit introduces support for Kotlin Value Classes which are designed for a more expressive domain model to make underlying concepts explicit. Spring Data can now read and write types that define properties using Value Classes. The support covers reflection based instantiation of Kotlin inline class, nullability and defaulting permutations as well as value classes with generics. Closes: #1947 Original Pull Request: #2866
Guard usage of KotlinReflectUtils with type presence check. Extend tests to cover primitive arrays. Move methods from KotlinValueUtils to KotlinReflectUtils. Move copy value cache to KotlinCopyMethod. Original Pull Request: #2866
merged to main development line. |
Original Pull Request: #2866
KClass<?> kotlinClass = JvmClassMappingKt.getKotlinClass(type); | ||
|
||
for (KCallable<?> member : kotlinClass.getMembers()) { | ||
if (member instanceof KProperty<?> kp && isValueClass(kp.getReturnType())) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mp911de Sorry for trespassing, but I believe this might work incorrectly in case there are unrelated properties in the class. For example:
@JvmInline
value class Z(val value: String)
data class D(val x: Int) {
val unrelated1 = Z("1")
val Any.unrelated2: Z get() = Z("2")
}
hasValueClassProperty
will return true for the class D
, but it probably should be false (if I understood call sites correctly).
I suppose you're interested in finding only if any property in the primary constructor has a value class type? For that you need to take only non-extension properties (i.e. KClass.memberProperties
) whose names are equal to the parameters of the primary constructor.
|
||
if (kClass.isValue()) { | ||
|
||
for (KCallable<?> member : kClass.getMembers()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mp911de Similarly to the above, this should use memberProperties
, otherwise it'll fail on something like this:
@JvmInline
value class Z(val value: String) {
val String.unrelated: String get() = this
}
|
||
if (kClass.isValue()) { | ||
|
||
wrapperConstructor = kClass.getConstructors().iterator().next(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mp911de There's no guarantee that the first constructor is the primary one, nor that it has any parameters, so this can fail on something like this:
@JvmInline
value class Z(val value: String) {
constructor() : this("Fail")
}
I recommend to use primaryConstructor
instead.
|
||
KClass<?> nestedClass; | ||
|
||
// bound flattening |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mp911de You can use jvmErasure
for this.
We now support instantiation and mutation of types using Kotlin Value (
@JvmInline
) classes:Value classes are typically flattened into their value type (component type) if the type at the declaration site does not change. Nullable value classes will be boxed.
Boxed values result in being recognized as entities.
The following components are affected by this change:
KotlinBeanInfoFactory
EntityInstantiator
PersistentPropertyAccessorFactory
Closes #2806