[#7324] Support Kotlin data classes in DefaultRecordMapper

This commit is contained in:
Vojtech Polivka 2018-03-19 13:51:57 -04:00
parent 454d9e91ba
commit b807eb3b46
3 changed files with 77 additions and 0 deletions

View File

@ -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>

View File

@ -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

View File

@ -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