[#7324] Support Kotlin data classes in DefaultRecordMapper
This commit is contained in:
parent
454d9e91ba
commit
b807eb3b46
@ -101,6 +101,11 @@
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-reflect</artifactId>
|
||||
<version>1.2.30</version>
|
||||
</dependency>
|
||||
|
||||
<!-- From JDK 9 onwards, the JAXB dependency needs to be made explicit -->
|
||||
<dependency>
|
||||
|
||||
@ -50,6 +50,7 @@ import static org.jooq.impl.Tools.getMatchingMembers;
|
||||
import static org.jooq.impl.Tools.getMatchingSetters;
|
||||
import static org.jooq.impl.Tools.getPropertyName;
|
||||
import static org.jooq.impl.Tools.hasColumnAnnotations;
|
||||
import static org.jooq.impl.Tools.fieldNameStrings;
|
||||
import static org.jooq.tools.reflect.Reflect.accessible;
|
||||
|
||||
import java.beans.ConstructorProperties;
|
||||
@ -79,6 +80,11 @@ import java.util.stream.Stream;
|
||||
|
||||
import javax.persistence.Column;
|
||||
|
||||
import kotlin.jvm.JvmClassMappingKt;
|
||||
import kotlin.reflect.KClass;
|
||||
import kotlin.reflect.KFunction;
|
||||
import kotlin.reflect.KParameter;
|
||||
import kotlin.reflect.full.KClasses;
|
||||
import org.jooq.Attachable;
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.Field;
|
||||
@ -343,6 +349,33 @@ public class DefaultRecordMapper<R extends Record, E> implements RecordMapper<R,
|
||||
return;
|
||||
}
|
||||
|
||||
// [#7324] Map Kotlin data classes
|
||||
KClass<? extends E> kotlinClass = JvmClassMappingKt.getKotlinClass(type);
|
||||
if (kotlinClass.isData()) {
|
||||
KFunction<? extends E> primaryConstructor = KClasses.getPrimaryConstructor(kotlinClass);
|
||||
List<KParameter> parameters = primaryConstructor.getParameters();
|
||||
|
||||
if (parameters.size() != fields.length) {
|
||||
throw new MappingException("Primary constructor of Kotlin data class " + type + " did not match row type " + rowType);
|
||||
}
|
||||
|
||||
for (String fieldName : fieldNameStrings(fields)) {
|
||||
String name = StringUtils.toCamelCaseLC(fieldName);
|
||||
boolean found = false;
|
||||
for (KParameter kParameter : parameters) {
|
||||
String parameterName = kParameter.getName();
|
||||
if (name.equals(parameterName)) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
throw new MappingException("Primary constructor of Kotlin data class " + type + " did not match row type " + rowType);
|
||||
}
|
||||
}
|
||||
delegate = new KotlinDataClassMapper(primaryConstructor);
|
||||
return;
|
||||
}
|
||||
|
||||
// [#1340] Allow for using non-public default constructors
|
||||
try {
|
||||
delegate = new MutablePOJOMapper(new ConstructorCall<E>(accessible(type.getDeclaredConstructor())), instance);
|
||||
@ -981,6 +1014,44 @@ public class DefaultRecordMapper<R extends Record, E> implements RecordMapper<R,
|
||||
}
|
||||
}
|
||||
|
||||
private class KotlinDataClassMapper implements RecordMapper<R, E> {
|
||||
|
||||
private final KFunction<? extends E> constructor;
|
||||
private final List<String> parameterNames;
|
||||
private final Class[] parameterTypes;
|
||||
private final Object[] parameterValues;
|
||||
|
||||
KotlinDataClassMapper(KFunction<? extends E> constructor) {
|
||||
this.constructor = constructor;
|
||||
int n = constructor.getParameters().size();
|
||||
this.parameterNames = new ArrayList<>(n);
|
||||
this.parameterValues = new Object[n];
|
||||
this.parameterTypes = new Class[n];
|
||||
|
||||
List<KParameter> parameters = constructor.getParameters();
|
||||
for (int i = 0; i < parameters.size(); i++) {
|
||||
KParameter kParam = parameters.get(i);
|
||||
parameterNames.add(kParam.getName());
|
||||
parameterTypes[i] = JvmClassMappingKt.getJavaClass(((KClass<?>) kParam.getType().getClassifier()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public E map(R record) {
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
String name = StringUtils.toCamelCaseLC(fields[i].getName());
|
||||
int index = parameterNames.indexOf(name);
|
||||
if (index < 0) {
|
||||
throw new MappingException("An error ocurred when mapping record to " + type);
|
||||
}
|
||||
parameterValues[index] = record.get(i);
|
||||
}
|
||||
|
||||
Object[] converted = Convert.convert(parameterValues, parameterTypes);
|
||||
return constructor.call(converted);
|
||||
}
|
||||
}
|
||||
|
||||
private static <E> E attach(E attachable, Record record) {
|
||||
// [#2869] Attach the mapped outcome if it is Attachable and if the context's
|
||||
// Settings.attachRecords flag is set
|
||||
|
||||
@ -55,6 +55,7 @@ Authors and contributors of jOOQ or parts of jOOQ in alphabetical order:
|
||||
- Victor Z. Peng
|
||||
- Vladimir Kulev
|
||||
- Vladimir Vinogradov
|
||||
- Vojtech Polivka
|
||||
- Wang Gaoyuan
|
||||
- Zoltan Tamasi
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user