Kotlin data class support for `FlatFileItemReaderBuilder`
Please do a quick search on Github issues first, the feature you are about to request might have already been requested.
Expected Behavior
Make FlatFileItemReaderBuilder detect whether the target type is Kotlin data class and sets proper FieldSetMapper which is not BeanWrapperFieldSetMapper.
RecordFieldSetMapper works with a Kotlin data class but we might be better to introduce a new dedicated FieldSetMapper.
Current Behavior
The FlatFileItemReaderBuilder only detects whether the target type is record or not. So it sets the BeanWrapperFieldSetMapper which instantiates the target type by the default constructor (no-args) and causes NotWritablePropertyException:
https://github.com/spring-projects/spring-batch/blob/d1bd7711c3947020cd786bd7f45dc26720bef430/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/builder/FlatFileItemReaderBuilder.java#L463-L467
Context
As a workaround, we might make the data class fields nullable and mutable like:
data class Player(var lastName: String? = null)
but as you know, it doesn't leverage the Kotlin's features.
Thank you for the suggestion.
Make FlatFileItemReaderBuilder detect whether the target type is Kotlin data class
Is there a reliable way to detect that? My concern with this request is that it would introduce code that is specific to Kotlin data classes (and possibly other JVM languages in the future if we get similar requests). As you mentioned, RecordFieldSetMapper works with a Kotlin data class so Kotlin users can just set that mapper or a custom one directly. Wdyt?
As you mentioned, RecordFieldSetMapper works with a Kotlin data class so Kotlin users can just set that mapper or a custom one directly.
You makes sense.
But when both targetType and fieldSetMapper are specified in the FlatFileItemReaderBuilder, the builder doesn't use the fieldSetMapper and do create a new one by the targetType. It might be better to warn when the fieldSetMapper is suppressed by the targetType.Supporting data class when the targetType is specified is just another improvement for Kotlin users.
Is there a reliable way to detect that? My concern with this request is that it would introduce code that is specific to Kotlin data classes (and possibly other JVM languages in the future if we get similar requests).
My first idea was that using KotlinDetector and JvmClassMappingKt as Spring Framework does:
https://github.com/spring-projects/spring-framework/blob/168276aaab14456cfcc1b0bd440a26e0682f8f90/spring-core/src/main/java/org/springframework/aot/hint/BindingReflectionHintsRegistrar.java#L120-L121
https://github.com/spring-projects/spring-framework/blob/168276aaab14456cfcc1b0bd440a26e0682f8f90/spring-core/src/main/java/org/springframework/aot/hint/BindingReflectionHintsRegistrar.java#L223-L224
Optional Kotlin dependency would not affect users who don't use Kotlin.
Or we'd be better to introduce a FieldSetMapperFactory that creates a new FieldSetMapper by the given targetType so that other JVM languages can easily integrate with. e.g.:
if (this.targetType != null || StringUtils.hasText(this.prototypeBeanName)) {
// this.fieldSetMapperFactories contains BeanWrapperFieldSetMapper and RecordFieldSetMapper by default
for (FieldSetMapperFactory factory : this.fieldSetMapperFactories) {
if (factory.canMap(this.targetType) {
lineMapper.setFieldSetMapper(factory.create(this.targetType);
break;
}
}
}
Is there a reliable way to detect that?
I've filled an issue to spring-framework about providing a way to detect a Kotlin data class.
https://github.com/spring-projects/spring-framework/issues/32937
I have decline the Framework issue created, and would advise to use KotlinDetector#isKotlinType to detect Kotlin classes and then using nested classed providing static methods using kotlin-reflect API from Java to perform such test, like what is done here.
Thank you for the updates, @0x1306e6d ! Based on @sdeleuze feedback, I would keep this type detection and mapper decision on the user's side rather than the framework side.
Thank you both for the follow-up on this. Appreciated your time!