DATACMNS-1180 - Fixed accessor lookup for generic properties.
In AbstractPersistentProperty, we now resolve the potentially generic return and parameter types of getters and setters. To achieve that Property has now been made aware of the actual owning type.
This commit is contained in:
@@ -513,12 +513,13 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
public void doWith(Field field) {
|
||||
|
||||
String fieldName = field.getName();
|
||||
TypeInformation<?> type = entity.getTypeInformation();
|
||||
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
|
||||
Property property = Optional.ofNullable(descriptors.get(fieldName))//
|
||||
.map(it -> Property.of(field, it))//
|
||||
.orElseGet(() -> Property.of(field));
|
||||
.map(it -> Property.of(type, field, it))//
|
||||
.orElseGet(() -> Property.of(type, field));
|
||||
|
||||
createAndRegisterProperty(property);
|
||||
|
||||
@@ -535,7 +536,7 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
|
||||
remainingDescriptors.values().stream() //
|
||||
.filter(Property::supportsStandalone) //
|
||||
.map(Property::of) //
|
||||
.map(it -> Property.of(entity.getTypeInformation(), it)) //
|
||||
.filter(PersistentPropertyFilter.INSTANCE::matches) //
|
||||
.forEach(this::createAndRegisterProperty);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import java.util.function.Function;
|
||||
|
||||
import org.springframework.data.util.Lazy;
|
||||
import org.springframework.data.util.Optionals;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -49,68 +50,75 @@ public class Property {
|
||||
private final Lazy<String> name;
|
||||
private final Lazy<String> toString;
|
||||
|
||||
private Property(Optional<Field> field, Optional<PropertyDescriptor> descriptor) {
|
||||
private Property(TypeInformation<?> type, Optional<Field> field, Optional<PropertyDescriptor> descriptor) {
|
||||
|
||||
Assert.notNull(type, "Type must not be null!");
|
||||
Assert.isTrue(Optionals.isAnyPresent(field, descriptor), "Either field or descriptor has to be given!");
|
||||
|
||||
this.field = field;
|
||||
this.descriptor = descriptor;
|
||||
|
||||
this.rawType = withFieldOrDescriptor(Field::getType, PropertyDescriptor::getPropertyType);
|
||||
this.rawType = withFieldOrDescriptor( //
|
||||
it -> type.getRequiredProperty(it.getName()).getType(), //
|
||||
it -> type.getRequiredProperty(it.getName()).getType() //
|
||||
);
|
||||
this.hashCode = Lazy.of(() -> withFieldOrDescriptor(Object::hashCode));
|
||||
this.name = Lazy.of(() -> withFieldOrDescriptor(Field::getName, FeatureDescriptor::getName));
|
||||
this.toString = Lazy.of(() -> withFieldOrDescriptor(Object::toString));
|
||||
|
||||
this.getter = descriptor.map(PropertyDescriptor::getReadMethod)//
|
||||
.filter(it -> getType() != null)//
|
||||
.filter(it -> getType().isAssignableFrom(it.getReturnType()));
|
||||
.filter(it -> getType().isAssignableFrom(type.getReturnType(it).getType()));
|
||||
|
||||
this.setter = descriptor.map(PropertyDescriptor::getWriteMethod)//
|
||||
.filter(it -> getType() != null)//
|
||||
.filter(it -> it.getParameterTypes()[0].isAssignableFrom(getType()));
|
||||
.filter(it -> type.getParameterTypes(it).get(0).getType().isAssignableFrom(getType()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Property} backed by the given field.
|
||||
*
|
||||
* @param type the owning type, must not be {@literal null}.
|
||||
* @param field must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Property of(Field field) {
|
||||
public static Property of(TypeInformation<?> type, Field field) {
|
||||
|
||||
Assert.notNull(field, "Field must not be null!");
|
||||
|
||||
return new Property(Optional.of(field), Optional.empty());
|
||||
return new Property(type, Optional.of(field), Optional.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Property} backed by the given {@link Field} and {@link PropertyDescriptor}.
|
||||
*
|
||||
* @param type the owning type, must not be {@literal null}.
|
||||
* @param field must not be {@literal null}.
|
||||
* @param descriptor must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Property of(Field field, PropertyDescriptor descriptor) {
|
||||
public static Property of(TypeInformation<?> type, Field field, PropertyDescriptor descriptor) {
|
||||
|
||||
Assert.notNull(field, "Field must not be null!");
|
||||
Assert.notNull(descriptor, "PropertyDescriptor must not be null!");
|
||||
|
||||
return new Property(Optional.of(field), Optional.of(descriptor));
|
||||
return new Property(type, Optional.of(field), Optional.of(descriptor));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Property} for the given {@link PropertyDescriptor}. The creation might fail if the given
|
||||
* property is not representing a proper property.
|
||||
*
|
||||
* @param type the owning type, must not be {@literal null}.
|
||||
* @param descriptor must not be {@literal null}.
|
||||
* @return
|
||||
* @see #supportsStandalone(PropertyDescriptor)
|
||||
*/
|
||||
public static Property of(PropertyDescriptor descriptor) {
|
||||
public static Property of(TypeInformation<?> type, PropertyDescriptor descriptor) {
|
||||
|
||||
Assert.notNull(descriptor, "PropertyDescriptor must not be null!");
|
||||
|
||||
return new Property(Optional.empty(), Optional.of(descriptor));
|
||||
return new Property(type, Optional.empty(), Optional.of(descriptor));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user