[jOOQ/jOOQ#16655] MULTISET nested projection's ContextConverters don't receive correct ConverterContext

This commit is contained in:
Lukas Eder 2024-06-10 13:40:56 +02:00
parent 948901a2b4
commit e7882b314e
8 changed files with 55 additions and 44 deletions

View File

@ -67,6 +67,7 @@ import static org.jooq.SQLDialect.TRINO;
// ...
import static org.jooq.SQLDialect.YUGABYTEDB;
import static org.jooq.impl.Internal.arrayType;
import static org.jooq.impl.Internal.converterContext;
import static org.jooq.impl.QOM.GenerationOption.STORED;
import static org.jooq.impl.QOM.GenerationOption.VIRTUAL;
import static org.jooq.impl.SQLDataType.BLOB;
@ -111,6 +112,7 @@ import org.jooq.Configuration;
import org.jooq.Context;
import org.jooq.ContextConverter;
import org.jooq.Converter;
import org.jooq.ConverterContext;
import org.jooq.DataType;
import org.jooq.Domain;
import org.jooq.EmbeddableRecord;
@ -831,7 +833,11 @@ implements
}
@Override
public /* non-final */ T convert(Object object) {
public final T convert(Object object) {
return convert(object, converterContext());
}
/* non-final */ T convert(Object object, ConverterContext cc) {
// [#1441] Avoid unneeded type conversions to improve performance
if (object == null)

View File

@ -67,6 +67,7 @@ import org.jooq.Attachable;
import org.jooq.CSVFormat;
import org.jooq.ChartFormat;
import org.jooq.Converter;
import org.jooq.ConverterContext;
import org.jooq.DataType;
import org.jooq.EmbeddableRecord;
import org.jooq.Field;
@ -718,10 +719,12 @@ implements
class TransferRecordState<R extends Record> implements ThrowingFunction<R, R, MappingException> {
private final Field<?>[] targetFields;
final ConverterContext converterContext;
final Field<?>[] targetFields;
TransferRecordState(Field<?>[] targetFields) {
this.targetFields = targetFields;
this.converterContext = converterContext(AbstractRecord.this);
}
@Override
@ -755,7 +758,7 @@ implements
Field<?> sourceField = field(targetField);
if (sourceField != null)
Tools.setValue(target, targetField, source, sourceField);
Tools.setValue(target, targetField, source, sourceField, converterContext);
}
}
@ -910,11 +913,13 @@ implements
* public for broader use...?
*/
protected final void from(Record source) {
ConverterContext cc = Tools.converterContext(this);
for (Field<?> field : fields.fields.fields) {
Field<?> sourceField = source.field(field);
if (sourceField != null && source.changed(sourceField))
Tools.setValue(this, field, source, sourceField);
Tools.setValue(this, field, source, sourceField, cc);
}
}

View File

@ -47,6 +47,7 @@ import org.jooq.CharacterSet;
import org.jooq.Collation;
import org.jooq.Configuration;
import org.jooq.Converter;
import org.jooq.ConverterContext;
import org.jooq.Converters;
import org.jooq.DataType;
import org.jooq.Field;
@ -300,7 +301,7 @@ final class ConvertedDataType<T, U> extends AbstractDataTypeX<U> {
}
@Override
public final U convert(Object object) {
final U convert(Object object, ConverterContext cc) {
if (getConverter().toType().isInstance(object))
return (U) object;
@ -316,7 +317,7 @@ final class ConvertedDataType<T, U> extends AbstractDataTypeX<U> {
// [#3200] Try to convert arbitrary objects to T
else
return ((ContextConverter<T, U>) getConverter()).from(delegate.convert(object), converterContext());
return ((ContextConverter<T, U>) getConverter()).from(delegate.convert(object, cc), cc);
}
@Override

View File

@ -37,6 +37,7 @@
*/
package org.jooq.impl;
import static org.jooq.impl.Tools.converterContext;
import static org.jooq.impl.Tools.getAnnotatedGetter;
import static org.jooq.impl.Tools.getAnnotatedMembers;
import static org.jooq.impl.Tools.getMatchingGetter;
@ -51,6 +52,7 @@ import java.util.List;
import java.util.Map;
import org.jooq.Configuration;
import org.jooq.ConverterContext;
import org.jooq.Field;
import org.jooq.Record;
import org.jooq.RecordType;
@ -80,6 +82,7 @@ public class DefaultRecordUnmapper<E, R extends Record> implements RecordUnmappe
private final Class<? extends AbstractRecord> recordType;
private final Field<?>[] fields;
private final Configuration configuration;
private final ConverterContext converterContext;
private RecordUnmapper<E, R> delegate;
public DefaultRecordUnmapper(Class<? extends E> type, RecordType<R> rowType, Configuration configuration) {
@ -89,6 +92,7 @@ public class DefaultRecordUnmapper<E, R extends Record> implements RecordUnmappe
this.recordType = Tools.recordType(rowType.size());
this.fields = rowType.fields();
this.configuration = configuration;
this.converterContext = converterContext(configuration);
init();
}
@ -115,31 +119,31 @@ public class DefaultRecordUnmapper<E, R extends Record> implements RecordUnmappe
return Tools.newRecord(false, recordType, row, configuration).operate(null);
}
private static final void setValue(Record record, Object source, java.lang.reflect.Field member, Field<?> field)
private static final void setValue(Record record, Object source, java.lang.reflect.Field member, Field<?> field, ConverterContext converterContext)
throws IllegalAccessException {
Class<?> mType = member.getType();
if (mType.isPrimitive()) {
if (mType == byte.class)
Tools.setValue(record, field, member.getByte(source));
Tools.setValue(record, field, member.getByte(source), converterContext);
else if (mType == short.class)
Tools.setValue(record, field, member.getShort(source));
Tools.setValue(record, field, member.getShort(source), converterContext);
else if (mType == int.class)
Tools.setValue(record, field, member.getInt(source));
Tools.setValue(record, field, member.getInt(source), converterContext);
else if (mType == long.class)
Tools.setValue(record, field, member.getLong(source));
Tools.setValue(record, field, member.getLong(source), converterContext);
else if (mType == float.class)
Tools.setValue(record, field, member.getFloat(source));
Tools.setValue(record, field, member.getFloat(source), converterContext);
else if (mType == double.class)
Tools.setValue(record, field, member.getDouble(source));
Tools.setValue(record, field, member.getDouble(source), converterContext);
else if (mType == boolean.class)
Tools.setValue(record, field, member.getBoolean(source));
Tools.setValue(record, field, member.getBoolean(source), converterContext);
else if (mType == char.class)
Tools.setValue(record, field, member.getChar(source));
Tools.setValue(record, field, member.getChar(source), converterContext);
}
else
Tools.setValue(record, field, member.get(source));
Tools.setValue(record, field, member.get(source), converterContext);
}
private final class ArrayUnmapper implements RecordUnmapper<E, R> {
@ -152,7 +156,7 @@ public class DefaultRecordUnmapper<E, R extends Record> implements RecordUnmappe
AbstractRecord record = (AbstractRecord) newRecord();
for (int i = 0; i < size && i < array.length; i++)
Tools.setValue(record, rowType.field(i), i, array[i]);
Tools.setValue(record, rowType.field(i), i, array[i], converterContext);
return (R) record;
}
@ -172,7 +176,7 @@ public class DefaultRecordUnmapper<E, R extends Record> implements RecordUnmappe
AbstractRecord record = (AbstractRecord) newRecord();
for (int i = 0; i < size && it.hasNext(); i++)
Tools.setValue(record, rowType.field(i), i, it.next());
Tools.setValue(record, rowType.field(i), i, it.next(), converterContext);
return (R) record;
}
@ -217,7 +221,7 @@ public class DefaultRecordUnmapper<E, R extends Record> implements RecordUnmappe
// Set only those values contained in the map
if (map.containsKey(name))
Tools.setValue(record, fields[i], map.get(name));
Tools.setValue(record, fields[i], map.get(name), converterContext);
}
return (R) record;
@ -255,9 +259,9 @@ public class DefaultRecordUnmapper<E, R extends Record> implements RecordUnmappe
// Use only the first applicable method or member
if (method != null)
Tools.setValue(record, field, method.invoke(source));
Tools.setValue(record, field, method.invoke(source), converterContext);
else if (members.size() > 0)
setValue(record, source, members.get(0), field);
setValue(record, source, members.get(0), field, converterContext);
}
return (R) record;

View File

@ -44,6 +44,7 @@ import org.jooq.CharacterSet;
import org.jooq.Collation;
import org.jooq.Configuration;
import org.jooq.Converter;
import org.jooq.ConverterContext;
import org.jooq.DataType;
import org.jooq.Field;
import org.jooq.Generator;
@ -136,13 +137,13 @@ final class LegacyConvertedDataType<T, U> extends DefaultDataType<U> {
@SuppressWarnings("unchecked")
@Override
public U convert(Object object) {
final U convert(Object object, ConverterContext cc) {
if (getConverter().toType().isInstance(object))
return (U) object;
// [#3200] Try to convert arbitrary objects to T
else
return ((ContextConverter<T, U>) getConverter()).from(delegate.convert(object), converterContext());
return ((ContextConverter<T, U>) getConverter()).from(delegate.convert(object, cc), cc);
}
@SuppressWarnings({ "unchecked", "rawtypes" })

View File

@ -45,13 +45,13 @@ import static org.jooq.impl.Tools.newRecord;
import java.sql.Array;
import java.sql.SQLException;
import java.sql.Struct;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.jooq.CharacterSet;
import org.jooq.Collation;
import org.jooq.ConverterContext;
import org.jooq.Field;
import org.jooq.Generator;
import org.jooq.Nullability;
@ -155,9 +155,9 @@ final class MultisetDataType<R extends Record> extends DefaultDataType<Result<R>
return recordType;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@SuppressWarnings({ "unchecked" })
@Override
public Result<R> convert(Object object) {
final Result<R> convert(Object object, ConverterContext cc) {
// [#12269] [#13403] Don't re-copy perfectly fine results.
if (object instanceof Result && ((Result<?>) object).fieldsRow().equals(row))
@ -187,11 +187,11 @@ final class MultisetDataType<R extends Record> extends DefaultDataType<Result<R>
return result;
}
else if (object instanceof Object[] a) {
return convert((Object) asList(a));
return convert(asList(a), cc);
}
else if (object instanceof Array a) {
try {
return convert((Object) asList((Object[]) a.getArray()));
return convert(asList((Object[]) a.getArray()), cc);
}
catch (SQLException e) {
throw new DataAccessException("Error while accessing array", e);
@ -200,6 +200,6 @@ final class MultisetDataType<R extends Record> extends DefaultDataType<Result<R>
else if (object == null)
return new ResultImpl<>(CONFIG.get(), row);
else
return super.convert(object);
return super.convert(object, cc);
}
}

View File

@ -50,6 +50,7 @@ import java.util.Map.Entry;
import org.jooq.CharacterSet;
import org.jooq.Collation;
import org.jooq.ConverterContext;
import org.jooq.Field;
import org.jooq.Generator;
import org.jooq.Nullability;
@ -158,7 +159,7 @@ final class RecordDataType<R extends Record> extends DefaultDataType<R> {
@SuppressWarnings("unchecked")
@Override
public R convert(Object object) {
final R convert(Object object, ConverterContext cc) {
// [#12269] [#13403] Don't re-copy perfectly fine results.
if (object instanceof Record && ((Record) object).fieldsRow().equals(row))
@ -188,6 +189,6 @@ final class RecordDataType<R extends Record> extends DefaultDataType<R> {
});
}
else
return super.convert(object);
return super.convert(object, cc);
}
}

View File

@ -3711,29 +3711,22 @@ final class Tools {
/**
* Type-safely copy a value from one record to another
*/
static final <T> void setValue(Record target, Field<T> targetField, Record source, Field<?> sourceField) {
setValue(target, targetField, source.get(sourceField));
}
/**
* Type-safely copy a value from one record to another
*/
static final <T> void setValue(AbstractRecord target, Field<T> targetField, int targetIndex, Record source, int sourceIndex) {
setValue(target, targetField, targetIndex, source.get(sourceIndex));
static final <T> void setValue(Record target, Field<T> targetField, Record source, Field<?> sourceField, ConverterContext cc) {
setValue(target, targetField, source.get(sourceField), cc);
}
/**
* Type-safely set a value to a record
*/
static final <T> void setValue(Record target, Field<T> targetField, Object value) {
target.set(targetField, targetField.getDataType().convert(value));
static final <T> void setValue(Record target, Field<T> targetField, Object value, ConverterContext cc) {
target.set(targetField, ((AbstractDataType<T>) targetField.getDataType()).convert(value, cc));
}
/**
* Type-safely set a value to a record
*/
static final <T> void setValue(AbstractRecord target, Field<T> targetField, int targetIndex, Object value) {
target.set(targetField, targetIndex, targetField.getDataType().convert(value));
static final <T> void setValue(AbstractRecord target, Field<T> targetField, int targetIndex, Object value, ConverterContext cc) {
target.set(targetField, targetIndex, ((AbstractDataType<T>) targetField.getDataType()).convert(value, cc));
}
/**