diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractDataType.java b/jOOQ/src/main/java/org/jooq/impl/AbstractDataType.java index 611a468cd2..bcd2bcc963 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractDataType.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractDataType.java @@ -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) diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java b/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java index 9d8d71ff4b..1aa604db18 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java @@ -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 implements ThrowingFunction { - 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); } } diff --git a/jOOQ/src/main/java/org/jooq/impl/ConvertedDataType.java b/jOOQ/src/main/java/org/jooq/impl/ConvertedDataType.java index 0e19631707..a26953ac0f 100644 --- a/jOOQ/src/main/java/org/jooq/impl/ConvertedDataType.java +++ b/jOOQ/src/main/java/org/jooq/impl/ConvertedDataType.java @@ -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 extends AbstractDataTypeX { } @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 extends AbstractDataTypeX { // [#3200] Try to convert arbitrary objects to T else - return ((ContextConverter) getConverter()).from(delegate.convert(object), converterContext()); + return ((ContextConverter) getConverter()).from(delegate.convert(object, cc), cc); } @Override diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultRecordUnmapper.java b/jOOQ/src/main/java/org/jooq/impl/DefaultRecordUnmapper.java index 39973d0afa..b506dee279 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DefaultRecordUnmapper.java +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultRecordUnmapper.java @@ -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 implements RecordUnmappe private final Class recordType; private final Field[] fields; private final Configuration configuration; + private final ConverterContext converterContext; private RecordUnmapper delegate; public DefaultRecordUnmapper(Class type, RecordType rowType, Configuration configuration) { @@ -89,6 +92,7 @@ public class DefaultRecordUnmapper 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 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 { @@ -152,7 +156,7 @@ public class DefaultRecordUnmapper 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 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 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 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; diff --git a/jOOQ/src/main/java/org/jooq/impl/LegacyConvertedDataType.java b/jOOQ/src/main/java/org/jooq/impl/LegacyConvertedDataType.java index ecd2d8f656..ecbae30e1c 100644 --- a/jOOQ/src/main/java/org/jooq/impl/LegacyConvertedDataType.java +++ b/jOOQ/src/main/java/org/jooq/impl/LegacyConvertedDataType.java @@ -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 extends DefaultDataType { @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) getConverter()).from(delegate.convert(object), converterContext()); + return ((ContextConverter) getConverter()).from(delegate.convert(object, cc), cc); } @SuppressWarnings({ "unchecked", "rawtypes" }) diff --git a/jOOQ/src/main/java/org/jooq/impl/MultisetDataType.java b/jOOQ/src/main/java/org/jooq/impl/MultisetDataType.java index b816938249..4aa8b5eff0 100644 --- a/jOOQ/src/main/java/org/jooq/impl/MultisetDataType.java +++ b/jOOQ/src/main/java/org/jooq/impl/MultisetDataType.java @@ -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 extends DefaultDataType return recordType; } - @SuppressWarnings({ "unchecked", "rawtypes" }) + @SuppressWarnings({ "unchecked" }) @Override - public Result convert(Object object) { + final Result 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 extends DefaultDataType 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 extends DefaultDataType else if (object == null) return new ResultImpl<>(CONFIG.get(), row); else - return super.convert(object); + return super.convert(object, cc); } } diff --git a/jOOQ/src/main/java/org/jooq/impl/RecordDataType.java b/jOOQ/src/main/java/org/jooq/impl/RecordDataType.java index 5d0c963975..ddc91b55f6 100644 --- a/jOOQ/src/main/java/org/jooq/impl/RecordDataType.java +++ b/jOOQ/src/main/java/org/jooq/impl/RecordDataType.java @@ -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 extends DefaultDataType { @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 extends DefaultDataType { }); } else - return super.convert(object); + return super.convert(object, cc); } } diff --git a/jOOQ/src/main/java/org/jooq/impl/Tools.java b/jOOQ/src/main/java/org/jooq/impl/Tools.java index cbfe3f53a6..14eb3b2947 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Tools.java +++ b/jOOQ/src/main/java/org/jooq/impl/Tools.java @@ -3711,29 +3711,22 @@ final class Tools { /** * Type-safely copy a value from one record to another */ - static final void setValue(Record target, Field targetField, Record source, Field sourceField) { - setValue(target, targetField, source.get(sourceField)); - } - - /** - * Type-safely copy a value from one record to another - */ - static final void setValue(AbstractRecord target, Field targetField, int targetIndex, Record source, int sourceIndex) { - setValue(target, targetField, targetIndex, source.get(sourceIndex)); + static final void setValue(Record target, Field targetField, Record source, Field sourceField, ConverterContext cc) { + setValue(target, targetField, source.get(sourceField), cc); } /** * Type-safely set a value to a record */ - static final void setValue(Record target, Field targetField, Object value) { - target.set(targetField, targetField.getDataType().convert(value)); + static final void setValue(Record target, Field targetField, Object value, ConverterContext cc) { + target.set(targetField, ((AbstractDataType) targetField.getDataType()).convert(value, cc)); } /** * Type-safely set a value to a record */ - static final void setValue(AbstractRecord target, Field targetField, int targetIndex, Object value) { - target.set(targetField, targetIndex, targetField.getDataType().convert(value)); + static final void setValue(AbstractRecord target, Field targetField, int targetIndex, Object value, ConverterContext cc) { + target.set(targetField, targetIndex, ((AbstractDataType) targetField.getDataType()).convert(value, cc)); } /**