[jOOQ/jOOQ#12704] DefaultRecordUnmapper.IterableUnmapper uses name based

field access instead of index based ones, leading to ambiguities
This commit is contained in:
Lukas Eder 2021-12-08 11:22:36 +01:00
parent c079eac3c9
commit 82a565f566
5 changed files with 59 additions and 69 deletions

View File

@ -408,6 +408,10 @@ abstract class AbstractRecord extends AbstractStore implements Record {
public final <T> void set(Field<T> field, T value) {
int index = fields.indexOf(field);
set(field, index, value);
}
final <T> void set(Field<T> field, int index, T value) {
if (index >= 0)
set(index, field, value);
else if (Tools.nonReplacingEmbeddable(field)) {
@ -904,109 +908,93 @@ abstract class AbstractRecord extends AbstractStore implements Record {
return (@NotNull E) mapper.map(this);
}
private final void from0(Object source, FieldsImpl f) {
private final void from0(Object source, int[] targetIndexMapping) {
if (source == null) return;
// [#2520] TODO: Benchmark this from() method. There's probably a better implementation
from(Tools.configuration(this).recordUnmapperProvider().provide(source.getClass(), f).unmap(prepareArrayForUnmap(source, f)));
from(
Tools.configuration(this).recordUnmapperProvider().provide(source.getClass(), (FieldsImpl) fields.fields).unmap(source),
targetIndexMapping
);
// [#2700] [#3582] If a POJO attribute is NULL, but the column is NOT NULL
// then we should let the database apply DEFAULT values
resetChangedOnNotNull(this);
}
private final Object prepareArrayForUnmap(Object source, FieldsImpl f) {
if (source instanceof Object[]) { Object[] array = (Object[]) source;
if (array.length != f.size()) {
Object[] result = new Object[f.size()];
for (int i = 0; i < result.length; i++) {
int index = fields.indexOf(f.field(i));
result[i] = index >= 0 && index < array.length ? array[index] : null;
}
return result;
}
else
return source;
}
else
return source;
}
@Override
public final void from(Object source) {
from0(source, fields.fields);
from0(source, null);
}
@Override
public final void from(Object source, Field<?>... f) {
from0(source, new FieldsImpl(f));
from0(source, fields.fields.indexesOf(f));
}
@Override
public final void from(Object source, String... fieldNames) {
from(source, fields(fieldNames));
from0(source, fields.fields.indexesOf(fieldNames));
}
@Override
public final void from(Object source, Name... fieldNames) {
from(source, fields(fieldNames));
from0(source, fields.fields.indexesOf(fieldNames));
}
@Override
public final void from(Object source, int... fieldIndexes) {
from(source, fields(fieldIndexes));
from0(source, fieldIndexes);
}
@Override
public final void fromMap(Map<String, ?> map) {
from(map, fields());
from(map);
}
@Override
public final void fromMap(Map<String, ?> map, Field<?>... f) {
from0(map, new FieldsImpl(f));
from(map, f);
}
@Override
public final void fromMap(Map<String, ?> map, String... fieldNames) {
fromMap(map, fields(fieldNames));
from(map, fieldNames);
}
@Override
public final void fromMap(Map<String, ?> map, Name... fieldNames) {
fromMap(map, fields(fieldNames));
from(map, fieldNames);
}
@Override
public final void fromMap(Map<String, ?> map, int... fieldIndexes) {
fromMap(map, fields(fieldIndexes));
from(map, fieldIndexes);
}
@Override
public final void fromArray(Object... array) {
fromArray(array, fields());
from(array);
}
@Override
public final void fromArray(Object[] array, Field<?>... f) {
from0(array, new FieldsImpl(f));
from(array, f);
}
@Override
public final void fromArray(Object[] array, String... fieldNames) {
fromArray(array, fields(fieldNames));
from(array, fieldNames);
}
@Override
public final void fromArray(Object[] array, Name... fieldNames) {
fromArray(array, fields(fieldNames));
from(array, fieldNames);
}
@Override
public final void fromArray(Object[] array, int... fieldIndexes) {
fromArray(array, fields(fieldIndexes));
from(array, fieldIndexes);
}
/**
@ -1022,6 +1010,18 @@ abstract class AbstractRecord extends AbstractStore implements Record {
}
}
final void from(Record source, int[] indexMapping) {
int s = source.size();
int t = indexMapping == null ? s : indexMapping.length;
for (int i = 0; i < s && i < t; i++) {
int j = indexMapping == null ? i : indexMapping[i];
if (source.field(j) != null && source.changed(j))
Tools.setValue(this, field(j), j, source, j);
}
}
// -------------------------------------------------------------------------
// Formatting methods
// -------------------------------------------------------------------------

View File

@ -135,19 +135,15 @@ public class DefaultRecordUnmapper<E, R extends Record> implements RecordUnmappe
private final class ArrayUnmapper implements RecordUnmapper<E, R> {
@SuppressWarnings({ "unchecked", "rawtypes" })
@SuppressWarnings({ "unchecked" })
@Override
public final R unmap(E source) {
if (source instanceof Object[]) { Object[] array = (Object[]) source;
int size = rowType.size();
Record record = newRecord();
AbstractRecord record = (AbstractRecord) newRecord();
for (int i = 0; i < size && i < array.length; i++) {
Field field = rowType.field(i);
if (rowType.field(field) != null)
Tools.setValue(record, field, array[i]);
}
for (int i = 0; i < size && i < array.length; i++)
Tools.setValue(record, rowType.field(i), i, array[i]);
return (R) record;
}
@ -158,20 +154,16 @@ public class DefaultRecordUnmapper<E, R extends Record> implements RecordUnmappe
private final class IterableUnmapper implements RecordUnmapper<E, R> {
@SuppressWarnings({ "unchecked", "rawtypes" })
@SuppressWarnings({ "unchecked" })
@Override
public final R unmap(E source) {
if (source instanceof Iterable) { Iterable<?> iterable = (Iterable<?>) source;
Iterator<?> it = iterable.iterator();
int size = rowType.size();
Record record = newRecord();
AbstractRecord record = (AbstractRecord) newRecord();
for (int i = 0; i < size && it.hasNext(); i++) {
Field field = rowType.field(i);
if (rowType.field(field) != null)
Tools.setValue(record, field, it.next());
}
for (int i = 0; i < size && it.hasNext(); i++)
Tools.setValue(record, rowType.field(i), i, it.next());
return (R) record;
}

View File

@ -49,9 +49,7 @@ import java.sql.SQLWarning;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
import org.jooq.Configuration;
@ -63,7 +61,6 @@ import org.jooq.Name;
import org.jooq.Record;
import org.jooq.RecordMapper;
import org.jooq.RecordType;
import org.jooq.Result;
import org.jooq.Row;
import org.jooq.SelectField;
import org.jooq.Table;
@ -473,10 +470,6 @@ final class FieldsImpl<R extends Record> extends AbstractQueryPart implements Re
return dataType(indexOrFail(this, fieldName));
}
/**
* @deprecated - 3.14.5 - [#11058] - These are used for the deprecated interning feature only.
*/
@Deprecated
final int[] indexesOf(Field<?>... f) {
int[] result = new int[f.length];
@ -486,10 +479,6 @@ final class FieldsImpl<R extends Record> extends AbstractQueryPart implements Re
return result;
}
/**
* @deprecated - 3.14.5 - [#11058] - These are used for the deprecated interning feature only.
*/
@Deprecated
final int[] indexesOf(String... fieldNames) {
int[] result = new int[fieldNames.length];
@ -499,10 +488,6 @@ final class FieldsImpl<R extends Record> extends AbstractQueryPart implements Re
return result;
}
/**
* @deprecated - 3.14.5 - [#11058] - These are used for the deprecated interning feature only.
*/
@Deprecated
final int[] indexesOf(Name... fieldNames) {
int[] result = new int[fieldNames.length];
@ -512,7 +497,6 @@ final class FieldsImpl<R extends Record> extends AbstractQueryPart implements Re
return result;
}
@Override
public final void accept(Context<?> ctx) {
ctx.visit(wrap(fields));

View File

@ -3154,6 +3154,13 @@ final class Tools {
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));
}
/**
* Type-safely set a value to a record
*/
@ -3161,6 +3168,13 @@ final class Tools {
target.set(targetField, targetField.getDataType().convert(value));
}
/**
* 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));
}
/**
* [#2591] Type-safely copy a value from one record to another, preserving flags.
*/

View File

@ -105,7 +105,7 @@ final class XMLHandler<R extends Record> extends DefaultHandler {
XMLHandler(DSLContext ctx, AbstractRow<R> row, Class<? extends R> recordType) {
this.ctx = ctx;
this.states = new ArrayDeque<>();
s = new State<>(row, recordType);
this.s = new State<>(row, recordType);
}
Result<R> read(String string) {