[jOOQ/jOOQ#6598] Fixed also @ConstructorProperties mapping

This commit is contained in:
Lukas Eder 2020-03-26 15:42:51 +01:00
parent 622b07b1e0
commit 8fba879f62

View File

@ -39,10 +39,8 @@ package org.jooq.impl;
import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;
import static java.util.Collections.nCopies;
import static org.jooq.impl.DSL.field;
import static org.jooq.impl.DSL.name;
import static org.jooq.impl.Tools.EMPTY_FIELD;
import static org.jooq.impl.Tools.getAnnotatedGetter;
import static org.jooq.impl.Tools.getAnnotatedMembers;
import static org.jooq.impl.Tools.getAnnotatedSetters;
@ -386,7 +384,7 @@ public class DefaultRecordMapper<R extends Record, E> implements RecordMapper<R,
ConstructorProperties properties = constructor.getAnnotation(ConstructorProperties.class);
if (properties != null) {
delegate = new ImmutablePOJOMapperWithParameterNames(constructor, Arrays.asList(properties.value()));
delegate = new ImmutablePOJOMapperWithParameterNames(constructor, Arrays.asList(properties.value()), true);
return;
}
}
@ -435,7 +433,7 @@ public class DefaultRecordMapper<R extends Record, E> implements RecordMapper<R,
}
Constructor<E> javaConstructor = (Constructor<E>) this.type.getConstructor(parameterTypes);
delegate = new ImmutablePOJOMapperWithParameterNames(javaConstructor, parameterNames);
delegate = new ImmutablePOJOMapperWithParameterNames(javaConstructor, parameterNames, true);
return;
}
}
@ -466,7 +464,7 @@ public class DefaultRecordMapper<R extends Record, E> implements RecordMapper<R,
Parameter[] parameters = constructor.getParameters();
if (parameters != null && parameters.length > 0)
delegate = new ImmutablePOJOMapperWithParameterNames(constructor, collectParameterNames(parameters));
delegate = new ImmutablePOJOMapperWithParameterNames(constructor, collectParameterNames(parameters), supportsNesting);
}
@ -487,7 +485,7 @@ public class DefaultRecordMapper<R extends Record, E> implements RecordMapper<R,
Parameter[] parameters = constructor.getParameters();
if (parameters != null && parameters.length > 0) {
delegate = new ImmutablePOJOMapperWithParameterNames(constructor, collectParameterNames(parameters));
delegate = new ImmutablePOJOMapperWithParameterNames(constructor, collectParameterNames(parameters), true);
return;
}
}
@ -684,22 +682,22 @@ public class DefaultRecordMapper<R extends Record, E> implements RecordMapper<R,
*/
private class MutablePOJOMapper implements RecordMapper<R, E> {
private final Callable<E> constructor;
private final boolean useAnnotations;
private final List<java.lang.reflect.Field>[] members;
private final List<java.lang.reflect.Method>[] methods;
private final Map<String, List<RecordMapper<R, Object>>> nested;
private final E instance;
private final Callable<E> constructor;
private final boolean useAnnotations;
private final List<java.lang.reflect.Field>[] members;
private final List<java.lang.reflect.Method>[] methods;
private Map<String, List<RecordMapper<Record, Object>>> nestedMappers;
private Map<String, List<Field<?>>> nestedMappedFields;
private Map<String, List<Integer>> nestedIndexLookup;
private final E instance;
MutablePOJOMapper(Callable<E> constructor, E instance) {
this.constructor = constructor;
this.useAnnotations = hasColumnAnnotations(configuration, type);
this.members = new List[fields.length];
this.methods = new List[fields.length];
this.nested = new HashMap<>();
this.instance = instance;
Map<String, Field<?>[]> nestedFields = new HashMap<>();
for (int i = 0; i < fields.length; i++) {
Field<?> field = fields[i];
String name = field.getName();
@ -718,13 +716,22 @@ public class DefaultRecordMapper<R extends Record, E> implements RecordMapper<R,
if (dot > -1) {
String prefix = name.substring(0, dot);
Field<?>[] f = nestedFields.get(prefix);
if (f == null) {
f = nCopies(fields.length, field("")).toArray(EMPTY_FIELD);
nestedFields.put(prefix, f);
if (nestedMappedFields == null) {
this.nestedMappers = new HashMap<>();
this.nestedMappedFields = new HashMap<>();
this.nestedIndexLookup = new HashMap<>();
}
f[i] = field(name(name.substring(prefix.length() + 1)), field.getDataType());
List<Field<?>> f = nestedMappedFields.get(prefix);
if (f == null)
nestedMappedFields.put(prefix, f = new ArrayList<>());
List<Integer> indexes = nestedIndexLookup.get(prefix);
if (indexes == null)
nestedIndexLookup.put(prefix, indexes = new ArrayList<>());
f.add(field(name(name.substring(prefix.length() + 1)), field.getDataType()));
indexes.add(i);
members[i] = Collections.emptyList();
methods[i] = Collections.emptyList();
@ -738,25 +745,27 @@ public class DefaultRecordMapper<R extends Record, E> implements RecordMapper<R,
}
}
for (Entry<String, Field<?>[]> entry : nestedFields.entrySet()) {
String prefix = entry.getKey();
List<RecordMapper<R, Object>> list = new ArrayList<>();
if (nestedMappedFields != null) {
for (Entry<String, List<Field<?>>> entry : nestedMappedFields.entrySet()) {
String prefix = entry.getKey();
List<RecordMapper<Record, Object>> list = new ArrayList<>();
for (java.lang.reflect.Field member : getMatchingMembers(configuration, type, prefix)) {
list.add(configuration
.recordMapperProvider()
.provide(new Fields<>(entry.getValue()), member.getType())
);
for (java.lang.reflect.Field member : getMatchingMembers(configuration, type, prefix)) {
list.add(configuration
.recordMapperProvider()
.provide(new Fields<>(entry.getValue()), member.getType())
);
}
for (Method method : getMatchingSetters(configuration, type, prefix)) {
list.add(configuration
.recordMapperProvider()
.provide(new Fields<>(entry.getValue()), method.getParameterTypes()[0])
);
}
nestedMappers.put(prefix, list);
}
for (Method method : getMatchingSetters(configuration, type, prefix)) {
list.add(configuration
.recordMapperProvider()
.provide(new Fields<>(entry.getValue()), method.getParameterTypes()[0])
);
}
nested.put(prefix, list);
}
}
@ -790,21 +799,29 @@ public class DefaultRecordMapper<R extends Record, E> implements RecordMapper<R,
}
}
for (Entry<String, List<RecordMapper<R, Object>>> entry : nested.entrySet()) {
String prefix = entry.getKey();
if (nestedMappers != null) {
for (Entry<String, List<RecordMapper<Record, Object>>> entry : nestedMappers.entrySet()) {
String prefix = entry.getKey();
for (RecordMapper<R, Object> mapper : entry.getValue()) {
Object value = mapper.map(record);
for (RecordMapper<Record, Object> mapper : entry.getValue()) {
RecordImplN rec = new RecordImplN(nestedMappedFields.get(prefix));
for (java.lang.reflect.Field member : getMatchingMembers(configuration, type, prefix)) {
List<Integer> indexes = nestedIndexLookup.get(prefix);
for (int index = 0; index < indexes.size(); index++)
rec.set(index, record.get(indexes.get(index)));
// [#935] Avoid setting final fields
if ((member.getModifiers() & Modifier.FINAL) == 0)
map(value, result, member);
Object value = mapper.map(rec);
for (java.lang.reflect.Field member : getMatchingMembers(configuration, type, prefix)) {
// [#935] Avoid setting final fields
if ((member.getModifiers() & Modifier.FINAL) == 0)
map(value, result, member);
}
for (Method method : getMatchingSetters(configuration, type, prefix))
method.invoke(result, value);
}
for (Method method : getMatchingSetters(configuration, type, prefix))
method.invoke(result, value);
}
}
@ -887,15 +904,15 @@ public class DefaultRecordMapper<R extends Record, E> implements RecordMapper<R,
*/
private class ImmutablePOJOMapper implements RecordMapper<R, E> {
private final Constructor<E> constructor;
private final Class<?>[] parameterTypes;
private final Constructor<E> constructor;
private final Class<?>[] parameterTypes;
private final boolean nested;
private final int[] nonNestedIndexLookup;
private final List<Integer>[] nestedIndexLookup;
private final List<Field<?>>[] nestedMappedFields;
private final RecordMapper<Record, Object>[] nestedMappers;
public ImmutablePOJOMapper(Constructor<E> constructor, Class<?>[] parameterTypes, boolean supportsNesting) {
ImmutablePOJOMapper(Constructor<E> constructor, Class<?>[] parameterTypes, boolean supportsNesting) {
this.constructor = accessible(constructor);
this.parameterTypes = parameterTypes;
this.nestedMappedFields = new List[prefixes().size()];
@ -948,16 +965,22 @@ public class DefaultRecordMapper<R extends Record, E> implements RecordMapper<R,
@Override
public final E map(R record) {
try {
return constructor.newInstance(nested
? mapNested(record)
: Convert.convert(record.intoArray(), parameterTypes)
);
return constructor.newInstance(nested ? mapNested(record) : mapNonnested(record));
}
catch (Exception e) {
throw new MappingException("An error ocurred when mapping record to " + type, e);
}
}
private final Object[] mapNonnested(R record) {
Object[] converted = new Object[parameterTypes.length];
for (int i = 0; i < converted.length; i++)
set(converted, i, record.get(i, parameterTypes[i]));
return converted;
}
private final Object[] mapNested(R record) {
Object[] converted = new Object[prefixes().size()];
@ -977,27 +1000,29 @@ public class DefaultRecordMapper<R extends Record, E> implements RecordMapper<R,
return converted;
}
void set(Object[] array, int i, Object value) {
array[i] = value;
}
}
/**
* Create an immutable POJO given a constructor and its associated JavaBeans
* {@link ConstructorProperties}
*/
private class ImmutablePOJOMapperWithParameterNames implements RecordMapper<R, E> {
private class ImmutablePOJOMapperWithParameterNames extends ImmutablePOJOMapper {
private final Constructor<E> constructor;
private final Class<?>[] parameterTypes;
private final List<String> propertyNames;
private final boolean useAnnotations;
private final List<java.lang.reflect.Field>[] members;
private final java.lang.reflect.Method[] methods;
private final Integer[] propertyIndexes;
ImmutablePOJOMapperWithParameterNames(Constructor<E> constructor, List<String> propertyNames) {
this.constructor = constructor;
ImmutablePOJOMapperWithParameterNames(Constructor<E> constructor, List<String> propertyNames, boolean supportsNesting) {
super(constructor, constructor.getParameterTypes(), supportsNesting);
this.propertyNames = propertyNames;
this.useAnnotations = hasColumnAnnotations(configuration, type);
this.parameterTypes = constructor.getParameterTypes();
this.members = new List[fields.length];
this.methods = new Method[fields.length];
this.propertyIndexes = new Integer[fields.length];
@ -1032,37 +1057,25 @@ public class DefaultRecordMapper<R extends Record, E> implements RecordMapper<R,
}
@Override
public final E map(R record) {
try {
Object[] parameterValues = new Object[parameterTypes.length];
void set(Object[] array, int i, Object value) {
if (propertyIndexes[i] != null) {
array[propertyIndexes[i]] = value;
}
else {
for (java.lang.reflect.Field member : members[i]) {
int index = propertyNames.indexOf(member.getName());
for (int i = 0; i < fields.length; i++) {
if (propertyIndexes[i] != null) {
parameterValues[propertyIndexes[i]] = record.get(i);
}
else {
for (java.lang.reflect.Field member : members[i]) {
int index = propertyNames.indexOf(member.getName());
if (index >= 0)
parameterValues[index] = record.get(i);
}
if (methods[i] != null) {
String name = getPropertyName(methods[i].getName());
int index = propertyNames.indexOf(name);
if (index >= 0)
parameterValues[index] = record.get(i);
}
}
if (index >= 0)
array[index] = value;
}
Object[] converted = Convert.convert(parameterValues, parameterTypes);
return accessible(constructor).newInstance(converted);
}
catch (Exception e) {
throw new MappingException("An error ocurred when mapping record to " + type, e);
if (methods[i] != null) {
String name = getPropertyName(methods[i].getName());
int index = propertyNames.indexOf(name);
if (index >= 0)
array[index] = value;
}
}
}
}