From cfbca6d72be09328ba043647fab820f138b7847e Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Fri, 3 Sep 2021 11:25:03 +0200 Subject: [PATCH] [jOOQ/jOOQ#12208] Deeply nested MULTISET mappings with ad-hoc conversion doesn't work when using reflection --- jOOQ/src/main/java/org/jooq/Converters.java | 5 ++++- .../java/org/jooq/impl/AbstractRecord.java | 10 ++++++---- .../org/jooq/impl/DefaultRecordMapper.java | 2 +- .../main/java/org/jooq/impl/FieldsImpl.java | 8 ++++---- jOOQ/src/main/java/org/jooq/impl/Tools.java | 18 +++++++++++++----- 5 files changed, 28 insertions(+), 15 deletions(-) diff --git a/jOOQ/src/main/java/org/jooq/Converters.java b/jOOQ/src/main/java/org/jooq/Converters.java index da6df6fa29..45e28780e2 100644 --- a/jOOQ/src/main/java/org/jooq/Converters.java +++ b/jOOQ/src/main/java/org/jooq/Converters.java @@ -223,5 +223,8 @@ public class Converters extends AbstractConverter { * {@link DataType#asConvertedDataTypeFrom(Function)} or * {@link DataType#asConvertedDataTypeTo(Function)} */ - static final class UnknownType {} + @Internal + public static final class UnknownType { + private UnknownType() {} + } } diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java b/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java index 1a7eaad807..cd47ac85df 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java @@ -332,8 +332,9 @@ abstract class AbstractRecord extends AbstractStore implements Record { } @Override - public final T get(Field field, Class type) { - return (T) converterOrFail(this, field.getType(), (Class) type).from(get(field)); + public final U get(Field field, Class type) { + Object t = get(field); + return (U) converterOrFail(this, t, (Class) field.getType(), type).from(t); } @Override @@ -347,8 +348,9 @@ abstract class AbstractRecord extends AbstractStore implements Record { } @Override - public final T get(int index, Class type) { - return (T) converterOrFail(this, field(safeIndex(index)).getType(), (Class) type).from(get(index)); + public final U get(int index, Class type) { + Object t = get(index); + return (U) converterOrFail(this, t, (Class) field(safeIndex(index)).getType(), type).from(t); } @Override diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultRecordMapper.java b/jOOQ/src/main/java/org/jooq/impl/DefaultRecordMapper.java index 9edd03837b..ed13f8b214 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DefaultRecordMapper.java +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultRecordMapper.java @@ -394,7 +394,7 @@ public class DefaultRecordMapper implements RecordMapper extends AbstractQueryPart implements Re @Override public final RecordMapper mapper(int fieldIndex, Configuration configuration, Class type) { - return mapper(fieldIndex, converterOrFail(configuration, fields[safeIndex(fieldIndex)].getType(), type)); + return mapper(fieldIndex, converterOrFail(configuration, null, fields[safeIndex(fieldIndex)].getType(), type)); } @Override @@ -121,7 +121,7 @@ final class FieldsImpl extends AbstractQueryPart implements Re @Override public final RecordMapper mapper(String fieldName, Configuration configuration, Class type) { - return mapper(fieldName, converterOrFail(configuration, field(indexOrFail(this, fieldName)).getType(), type)); + return mapper(fieldName, converterOrFail(configuration, null, field(indexOrFail(this, fieldName)).getType(), type)); } @Override @@ -141,7 +141,7 @@ final class FieldsImpl extends AbstractQueryPart implements Re @Override public final RecordMapper mapper(Name fieldName, Configuration configuration, Class type) { - return mapper(fieldName, converterOrFail(configuration, field(indexOrFail(this, fieldName)).getType(), type)); + return mapper(fieldName, converterOrFail(configuration, null, field(indexOrFail(this, fieldName)).getType(), type)); } @Override @@ -163,7 +163,7 @@ final class FieldsImpl extends AbstractQueryPart implements Re @SuppressWarnings({ "unchecked", "rawtypes" }) @Override public final RecordMapper mapper(Field field, Configuration configuration, Class type) { - return mapper(field, (Converter) converterOrFail(configuration, field.getType(), type)); + return mapper(field, (Converter) converterOrFail(configuration, null, field.getType(), type)); } @SuppressWarnings("unchecked") diff --git a/jOOQ/src/main/java/org/jooq/impl/Tools.java b/jOOQ/src/main/java/org/jooq/impl/Tools.java index 5185741e5c..3851d8c548 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Tools.java +++ b/jOOQ/src/main/java/org/jooq/impl/Tools.java @@ -247,6 +247,7 @@ import org.jooq.Configuration; import org.jooq.Context; import org.jooq.Converter; import org.jooq.ConverterProvider; +import org.jooq.Converters; import org.jooq.Cursor; import org.jooq.DMLQuery; import org.jooq.DSLContext; @@ -1253,11 +1254,18 @@ final class Tools { * Get a converter from a {@link ConverterProvider} or null if * no converter could be provided. */ - static final Converter converter(Configuration configuration, Class tType, Class uType) { + static final Converter converter(Configuration configuration, T instance, Class tType, Class uType) { Converter result = configuration(configuration).converterProvider().provide(tType, uType); if (result == null) result = CTX.configuration().converterProvider().provide(tType, uType); + + // [#11823] [#12208] The new ad-hoc conversion API tries to avoid the Class literal + // meaning there are perfectly reasonable API usages when using MULTISET + // where we can't decide on a converter prior to having an actual result + // type - so, let's try again if we have the result value. + if (result == null && tType == Converters.UnknownType.class) + result = converter(configuration, instance, (Class) (instance == null ? Object.class : instance.getClass()), uType); return result; } @@ -1266,8 +1274,8 @@ final class Tools { * Get a converter from a {@link ConverterProvider} or null if * no converter could be provided. */ - static final Converter converterOrFail(Configuration configuration, Class tType, Class uType) { - Converter result = converter(configuration, tType, uType); + static final Converter converterOrFail(Configuration configuration, T instance, Class tType, Class uType) { + Converter result = converter(configuration, instance, tType, uType); if (result == null) throw new DataTypeException("No Converter found for types " + tType.getName() + " and " + uType.getName()); @@ -1278,8 +1286,8 @@ final class Tools { /** * Get a converter from a {@link ConverterProvider}. */ - static final Converter converterOrFail(Attachable attachable, Class tType, Class uType) { - return converterOrFail(configuration(attachable), tType, uType); + static final Converter converterOrFail(Attachable attachable, T instance, Class tType, Class uType) { + return converterOrFail(configuration(attachable), instance, tType, uType); } /**