Revisit internal caching arrangements.
Introduce caching and reduce allocations on hot code paths. Closes: #4818 Original Pull Request: #4819
This commit is contained in:
committed by
Christoph Strobl
parent
5419414734
commit
1075a25df4
@@ -171,6 +171,7 @@ public class DefaultMongoTypeMapper extends DefaultTypeMapper<Bson> implements M
|
||||
this.typeKey = typeKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Alias readAliasFrom(Bson source) {
|
||||
|
||||
if (source instanceof List) {
|
||||
|
||||
@@ -27,6 +27,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiPredicate;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -130,6 +131,23 @@ public class MappingMongoConverter extends AbstractMongoConverter
|
||||
private static final String INCOMPATIBLE_TYPES = "Cannot convert %1$s of type %2$s into an instance of %3$s; Implement a custom Converter<%2$s, %3$s> and register it with the CustomConversions; Parent object was: %4$s";
|
||||
private static final String INVALID_TYPE_TO_READ = "Expected to read Document %s into type %s but didn't find a PersistentEntity for the latter";
|
||||
|
||||
private static final BiPredicate<MongoPersistentEntity<?>, MongoPersistentProperty> PROPERTY_FILTER = (e,
|
||||
property) -> {
|
||||
|
||||
if (property.isIdProperty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (e.isCreatorArgument(property)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!property.isReadable()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
public static final TypeInformation<Bson> BSON = TypeInformation.of(Bson.class);
|
||||
|
||||
protected static final Log LOGGER = LogFactory.getLog(MappingMongoConverter.class);
|
||||
@@ -368,7 +386,7 @@ public class MappingMongoConverter extends AbstractMongoConverter
|
||||
evaluator, spELContext);
|
||||
|
||||
readProperties(context, entity, convertingAccessor, documentAccessor, valueProvider, evaluator,
|
||||
Predicates.isTrue());
|
||||
(mongoPersistentProperties, mongoPersistentProperty) -> true);
|
||||
return (R) projectionFactory.createProjection(mappedType.getType(), accessor.getBean());
|
||||
}
|
||||
|
||||
@@ -518,6 +536,23 @@ public class MappingMongoConverter extends AbstractMongoConverter
|
||||
parameterProvider);
|
||||
}
|
||||
|
||||
class EvaluatingDocumentAccessor extends DocumentAccessor implements ValueExpressionEvaluator {
|
||||
|
||||
/**
|
||||
* Creates a new {@link DocumentAccessor} for the given {@link Document}.
|
||||
*
|
||||
* @param document must be a {@link Document} effectively, must not be {@literal null}.
|
||||
*/
|
||||
public EvaluatingDocumentAccessor(Bson document) {
|
||||
super(document);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T evaluate(String expression) {
|
||||
return expressionEvaluatorFactory.create(getDocument()).evaluate(expression);
|
||||
}
|
||||
}
|
||||
|
||||
private <S> S read(ConversionContext context, MongoPersistentEntity<S> entity, Document bson) {
|
||||
|
||||
S existing = context.findContextualEntity(entity, bson);
|
||||
@@ -525,19 +560,18 @@ public class MappingMongoConverter extends AbstractMongoConverter
|
||||
return existing;
|
||||
}
|
||||
|
||||
ValueExpressionEvaluator evaluator = expressionEvaluatorFactory.create(bson);
|
||||
DocumentAccessor documentAccessor = new DocumentAccessor(bson);
|
||||
|
||||
EvaluatingDocumentAccessor documentAccessor = new EvaluatingDocumentAccessor(bson);
|
||||
InstanceCreatorMetadata<MongoPersistentProperty> instanceCreatorMetadata = entity.getInstanceCreatorMetadata();
|
||||
|
||||
ParameterValueProvider<MongoPersistentProperty> provider = instanceCreatorMetadata != null
|
||||
&& instanceCreatorMetadata.hasParameters() ? getParameterProvider(context, entity, documentAccessor, evaluator)
|
||||
&& instanceCreatorMetadata.hasParameters()
|
||||
? getParameterProvider(context, entity, documentAccessor, documentAccessor)
|
||||
: NoOpParameterValueProvider.INSTANCE;
|
||||
|
||||
EntityInstantiator instantiator = instantiators.getInstantiatorFor(entity);
|
||||
S instance = instantiator.createInstance(entity, provider);
|
||||
|
||||
return populateProperties(context, entity, documentAccessor, evaluator, instance);
|
||||
return populateProperties(context, entity, documentAccessor, documentAccessor, instance);
|
||||
}
|
||||
|
||||
private <S> S populateProperties(ConversionContext context, MongoPersistentEntity<S> entity,
|
||||
@@ -559,9 +593,7 @@ public class MappingMongoConverter extends AbstractMongoConverter
|
||||
MongoDbPropertyValueProvider valueProvider = new MongoDbPropertyValueProvider(contextToUse, documentAccessor,
|
||||
evaluator, spELContext);
|
||||
|
||||
Predicate<MongoPersistentProperty> propertyFilter = isIdentifier(entity).or(isConstructorArgument(entity))
|
||||
.or(Predicates.negate(PersistentProperty::isReadable)).negate();
|
||||
readProperties(contextToUse, entity, accessor, documentAccessor, valueProvider, evaluator, propertyFilter);
|
||||
readProperties(contextToUse, entity, accessor, documentAccessor, valueProvider, evaluator, PROPERTY_FILTER);
|
||||
|
||||
return accessor.getBean();
|
||||
}
|
||||
@@ -606,13 +638,13 @@ public class MappingMongoConverter extends AbstractMongoConverter
|
||||
private void readProperties(ConversionContext context, MongoPersistentEntity<?> entity,
|
||||
PersistentPropertyAccessor<?> accessor, DocumentAccessor documentAccessor,
|
||||
MongoDbPropertyValueProvider valueProvider, ValueExpressionEvaluator evaluator,
|
||||
Predicate<MongoPersistentProperty> propertyFilter) {
|
||||
BiPredicate<MongoPersistentEntity<?>, MongoPersistentProperty> propertyFilter) {
|
||||
|
||||
DbRefResolverCallback callback = null;
|
||||
|
||||
for (MongoPersistentProperty prop : entity) {
|
||||
|
||||
if (!propertyFilter.test(prop)) {
|
||||
if (!propertyFilter.test(entity, prop)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1943,10 +1975,6 @@ public class MappingMongoConverter extends AbstractMongoConverter
|
||||
MongoDbPropertyValueProvider(ConversionContext context, DocumentAccessor accessor,
|
||||
ValueExpressionEvaluator evaluator, SpELContext spELContext) {
|
||||
|
||||
Assert.notNull(context, "ConversionContext must no be null");
|
||||
Assert.notNull(accessor, "DocumentAccessor must no be null");
|
||||
Assert.notNull(evaluator, "ValueExpressionEvaluator must not be null");
|
||||
|
||||
this.context = context;
|
||||
this.accessor = accessor;
|
||||
this.evaluator = evaluator;
|
||||
@@ -2359,9 +2387,6 @@ public class MappingMongoConverter extends AbstractMongoConverter
|
||||
public <S extends Object> S convert(Object source, TypeInformation<? extends S> typeHint,
|
||||
ConversionContext context) {
|
||||
|
||||
Assert.notNull(source, "Source must not be null");
|
||||
Assert.notNull(typeHint, "TypeInformation must not be null");
|
||||
|
||||
if (conversions.hasCustomReadTarget(source.getClass(), typeHint.getType())) {
|
||||
return (S) elementConverter.convert(source, typeHint);
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ import org.springframework.lang.Nullable;
|
||||
*/
|
||||
public class CachingMongoPersistentProperty extends BasicMongoPersistentProperty {
|
||||
|
||||
private final Lazy<Boolean> isEntity = Lazy.of(super::isEntity);
|
||||
private final Lazy<Boolean> isUnwrapped = Lazy.of(super::isUnwrapped);
|
||||
private final Lazy<Boolean> isIdProperty = Lazy.of(super::isIdProperty);
|
||||
private final Lazy<Boolean> isAssociation = Lazy.of(super::isAssociation);
|
||||
private final Lazy<DBRef> dbref = Lazy.of(super::getDBRef);
|
||||
@@ -58,6 +60,16 @@ public class CachingMongoPersistentProperty extends BasicMongoPersistentProperty
|
||||
super(property, owner, simpleTypeHolder, fieldNamingStrategy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEntity() {
|
||||
return isEntity.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnwrapped() {
|
||||
return isUnwrapped.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIdProperty() {
|
||||
return isIdProperty.get();
|
||||
|
||||
@@ -25,7 +25,11 @@ import org.springframework.util.ObjectUtils;
|
||||
* @author Christoph Strobl
|
||||
* @since 4.2
|
||||
*/
|
||||
public record FieldName(String name, Type type) {
|
||||
public record FieldName(String name, Type type, String[] parts) {
|
||||
|
||||
public FieldName(String name, Type type) {
|
||||
this(name, type, name.split("\\."));
|
||||
}
|
||||
|
||||
private static final String ID_KEY = "_id";
|
||||
|
||||
@@ -65,7 +69,7 @@ public record FieldName(String name, Type type) {
|
||||
return new String[] { name };
|
||||
}
|
||||
|
||||
return name.split("\\.");
|
||||
return parts;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user