Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b92ecc337 | ||
|
|
78899c757f | ||
|
|
a3861b607a | ||
|
|
ee4160997b | ||
|
|
aeeac56d19 | ||
|
|
e9c15eb169 | ||
|
|
7f223d1332 | ||
|
|
cffee123dc | ||
|
|
352376166a | ||
|
|
64b0096c7b | ||
|
|
fb905761a0 | ||
|
|
1e40448b70 | ||
|
|
530912d07f | ||
|
|
82331451ea | ||
|
|
6899567c01 | ||
|
|
0d869b3c23 | ||
|
|
d8ef0db1a9 |
2
Jenkinsfile
vendored
2
Jenkinsfile
vendored
@@ -3,7 +3,7 @@ pipeline {
|
||||
|
||||
triggers {
|
||||
pollSCM 'H/10 * * * *'
|
||||
upstream(upstreamProjects: "spring-data-commons/main", threshold: hudson.model.Result.SUCCESS)
|
||||
upstream(upstreamProjects: "spring-data-commons/2.6.x", threshold: hudson.model.Result.SUCCESS)
|
||||
}
|
||||
|
||||
options {
|
||||
|
||||
8
pom.xml
8
pom.xml
@@ -5,7 +5,7 @@
|
||||
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<version>3.3.1</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Spring Data MongoDB</name>
|
||||
@@ -15,7 +15,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data.build</groupId>
|
||||
<artifactId>spring-data-parent</artifactId>
|
||||
<version>2.6.0</version>
|
||||
<version>2.6.1</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
@@ -26,8 +26,8 @@
|
||||
<properties>
|
||||
<project.type>multi</project.type>
|
||||
<dist.id>spring-data-mongodb</dist.id>
|
||||
<springdata.commons>2.6.0</springdata.commons>
|
||||
<mongo>4.4.0</mongo>
|
||||
<springdata.commons>2.6.1</springdata.commons>
|
||||
<mongo>4.4.1</mongo>
|
||||
<mongo.reactivestreams>${mongo}</mongo.reactivestreams>
|
||||
<jmh.version>1.19</jmh.version>
|
||||
</properties>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<version>3.3.1</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<version>3.3.1</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<version>3.3.1</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -1803,8 +1803,9 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
||||
Document projections = new Document();
|
||||
|
||||
Fields fields = context.getFields(type);
|
||||
fields.forEach(it -> projections.append(it.getName(), 1));
|
||||
return context.getMappedObject(projections, type);
|
||||
|
||||
fields.forEach(it -> projections.append(it.getTarget(), 1));
|
||||
return projections;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mongodb.core.aggregation.ExposedFields.DirectFieldReference;
|
||||
@@ -122,13 +122,13 @@ public class TypeBasedAggregationOperationContext implements AggregationOperatio
|
||||
return AggregationOperationContext.super.getFields(type);
|
||||
}
|
||||
|
||||
List<String> fields = new ArrayList<>();
|
||||
List<Field> fields = new ArrayList<>();
|
||||
|
||||
for (MongoPersistentProperty property : entity) {
|
||||
fields.add(property.getName());
|
||||
fields.add(Fields.field(property.getName(), property.getFieldName()));
|
||||
}
|
||||
|
||||
return Fields.fields(fields.toArray(new String[0]));
|
||||
return Fields.from(fields.toArray(new Field[0]));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -142,12 +142,13 @@ public class TypeBasedAggregationOperationContext implements AggregationOperatio
|
||||
|
||||
/**
|
||||
* This toggle allows the {@link AggregationOperationContext context} to use any given field name without checking for
|
||||
* its existence. Typically the {@link AggregationOperationContext} fails when referencing unknown fields, those that
|
||||
* its existence. Typically, the {@link AggregationOperationContext} fails when referencing unknown fields, those that
|
||||
* are not present in one of the previous stages or the input source, throughout the pipeline.
|
||||
*
|
||||
* @param type The domain type to map fields to.
|
||||
* @return a more relaxed {@link AggregationOperationContext}.
|
||||
* @since 3.1
|
||||
* @see RelaxedTypeBasedAggregationOperationContext
|
||||
*/
|
||||
public AggregationOperationContext continueOnMissingFieldReference(Class<?> type) {
|
||||
return new RelaxedTypeBasedAggregationOperationContext(type, mappingContext, mapper);
|
||||
|
||||
@@ -19,6 +19,7 @@ import static org.springframework.data.mongodb.core.convert.ReferenceLookupDeleg
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
import org.springframework.data.mongodb.core.mapping.DBRef;
|
||||
import org.springframework.data.mongodb.core.mapping.DocumentReference;
|
||||
@@ -32,6 +33,7 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @author Anton Buzdalkin
|
||||
* @since 3.3
|
||||
*/
|
||||
public class DefaultReferenceResolver implements ReferenceResolver {
|
||||
@@ -41,8 +43,8 @@ public class DefaultReferenceResolver implements ReferenceResolver {
|
||||
|
||||
private final LookupFunction collectionLookupFunction = (filter, ctx) -> getReferenceLoader().fetchMany(filter, ctx);
|
||||
private final LookupFunction singleValueLookupFunction = (filter, ctx) -> {
|
||||
Object target = getReferenceLoader().fetchOne(filter, ctx);
|
||||
return target == null ? Collections.emptyList() : Collections.singleton(getReferenceLoader().fetchOne(filter, ctx));
|
||||
Document target = getReferenceLoader().fetchOne(filter, ctx);
|
||||
return target == null ? Collections.emptyList() : Collections.singleton(target);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.bson.types.ObjectId;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.core.CollectionFactory;
|
||||
@@ -123,6 +124,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
protected @Nullable String mapKeyDotReplacement = null;
|
||||
protected @Nullable CodecRegistryProvider codecRegistryProvider;
|
||||
|
||||
private MongoTypeMapper defaultTypeMapper;
|
||||
private SpELContext spELContext;
|
||||
private @Nullable EntityCallbacks entityCallbacks;
|
||||
private final DocumentPointerFactory documentPointerFactory;
|
||||
@@ -144,7 +146,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
this.dbRefResolver = dbRefResolver;
|
||||
|
||||
this.mappingContext = mappingContext;
|
||||
this.typeMapper = new DefaultMongoTypeMapper(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY, mappingContext,
|
||||
this.defaultTypeMapper = new DefaultMongoTypeMapper(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY, mappingContext,
|
||||
this::getWriteTarget);
|
||||
this.idMapper = new QueryMapper(this);
|
||||
|
||||
@@ -197,9 +199,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
* @param typeMapper the typeMapper to set. Can be {@literal null}.
|
||||
*/
|
||||
public void setTypeMapper(@Nullable MongoTypeMapper typeMapper) {
|
||||
this.typeMapper = typeMapper == null
|
||||
? new DefaultMongoTypeMapper(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY, mappingContext)
|
||||
: typeMapper;
|
||||
this.typeMapper = typeMapper;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -208,7 +208,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
*/
|
||||
@Override
|
||||
public MongoTypeMapper getTypeMapper() {
|
||||
return this.typeMapper;
|
||||
return this.typeMapper == null ? this.defaultTypeMapper : this.typeMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -257,6 +257,11 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
if (entityCallbacks == null) {
|
||||
setEntityCallbacks(EntityCallbacks.create(applicationContext));
|
||||
}
|
||||
|
||||
ClassLoader classLoader = applicationContext.getClassLoader();
|
||||
if (this.defaultTypeMapper instanceof BeanClassLoaderAware && classLoader != null) {
|
||||
((BeanClassLoaderAware) this.defaultTypeMapper).setBeanClassLoader(classLoader);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -301,7 +306,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
TypeInformation<? extends S> typeHint) {
|
||||
|
||||
Document document = bson instanceof BasicDBObject ? new Document((BasicDBObject) bson) : (Document) bson;
|
||||
TypeInformation<? extends S> typeToRead = typeMapper.readType(document, typeHint);
|
||||
TypeInformation<? extends S> typeToRead = getTypeMapper().readType(document, typeHint);
|
||||
Class<? extends S> rawType = typeToRead.getType();
|
||||
|
||||
if (conversions.hasCustomReadTarget(bson.getClass(), rawType)) {
|
||||
@@ -657,7 +662,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
BsonUtils.removeNullId(bson);
|
||||
|
||||
if (requiresTypeHint(entityType)) {
|
||||
typeMapper.writeType(type, bson);
|
||||
getTypeMapper().writeType(type, bson);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1099,7 +1104,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
|
||||
boolean notTheSameClass = !valueType.equals(reference);
|
||||
if (notTheSameClass) {
|
||||
typeMapper.writeType(valueType, bson);
|
||||
getTypeMapper().writeType(valueType, bson);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1307,7 +1312,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
Assert.notNull(bson, "Document must not be null!");
|
||||
Assert.notNull(targetType, "TypeInformation must not be null!");
|
||||
|
||||
Class<?> mapType = typeMapper.readType(bson, targetType).getType();
|
||||
Class<?> mapType = getTypeMapper().readType(bson, targetType).getType();
|
||||
|
||||
TypeInformation<?> keyType = targetType.getComponentType();
|
||||
TypeInformation<?> valueType = targetType.getMapValueType() == null ? ClassTypeInformation.OBJECT
|
||||
@@ -1326,7 +1331,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
|
||||
sourceMap.forEach((k, v) -> {
|
||||
|
||||
if (typeMapper.isTypeKey(k)) {
|
||||
if (getTypeMapper().isTypeKey(k)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1489,7 +1494,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
}
|
||||
}
|
||||
|
||||
if (typeMapper.isTypeKey(key)) {
|
||||
if (getTypeMapper().isTypeKey(key)) {
|
||||
|
||||
keyToRemove = key;
|
||||
|
||||
@@ -1660,6 +1665,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
target.conversions = conversions;
|
||||
target.spELContext = spELContext;
|
||||
target.setInstantiators(instantiators);
|
||||
target.defaultTypeMapper = defaultTypeMapper;
|
||||
target.typeMapper = typeMapper;
|
||||
target.setCodecRegistryProvider(dbFactory);
|
||||
target.afterPropertiesSet();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2021 the original author or authors.
|
||||
* Copyright 2011-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -1398,6 +1398,14 @@ public class QueryMapper {
|
||||
this.currentIndex = 0;
|
||||
}
|
||||
|
||||
String nextToken() {
|
||||
return pathParts.get(currentIndex + 1);
|
||||
}
|
||||
|
||||
boolean hasNexToken() {
|
||||
return pathParts.size() > currentIndex + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the property name while retaining potential positional operator {@literal $}.
|
||||
*
|
||||
@@ -1407,31 +1415,26 @@ public class QueryMapper {
|
||||
protected String mapPropertyName(MongoPersistentProperty property) {
|
||||
|
||||
StringBuilder mappedName = new StringBuilder(PropertyToFieldNameConverter.INSTANCE.convert(property));
|
||||
|
||||
boolean inspect = iterator.hasNext();
|
||||
|
||||
while (inspect) {
|
||||
|
||||
String partial = iterator.next();
|
||||
currentIndex++;
|
||||
|
||||
boolean isPositional = isPositionalParameter(partial) && property.isCollectionLike();
|
||||
if (property.isMap() && currentPropertyRoot.equals(partial) && iterator.hasNext()) {
|
||||
partial = iterator.next();
|
||||
currentIndex++;
|
||||
}
|
||||
|
||||
if (isPositional || property.isMap() && !currentPropertyRoot.equals(partial)) {
|
||||
mappedName.append(".").append(partial);
|
||||
}
|
||||
|
||||
inspect = isPositional && iterator.hasNext();
|
||||
if (!hasNexToken()) {
|
||||
return mappedName.toString();
|
||||
}
|
||||
|
||||
if (currentIndex + 1 < pathParts.size()) {
|
||||
currentIndex++;
|
||||
currentPropertyRoot = pathParts.get(currentIndex);
|
||||
String nextToken = nextToken();
|
||||
if (isPositionalParameter(nextToken)) {
|
||||
|
||||
mappedName.append(".").append(nextToken);
|
||||
currentIndex += 2;
|
||||
return mappedName.toString();
|
||||
}
|
||||
|
||||
if (property.isMap()) {
|
||||
|
||||
mappedName.append(".").append(nextToken);
|
||||
currentIndex += 2;
|
||||
return mappedName.toString();
|
||||
}
|
||||
|
||||
currentIndex++;
|
||||
return mappedName.toString();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2021 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,6 +25,16 @@ import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link IndexResolver} finds those {@link IndexDefinition}s to be created for a given class.
|
||||
* <p>
|
||||
* The {@link IndexResolver} considers index annotations like {@link Indexed}, {@link GeoSpatialIndexed},
|
||||
* {@link HashIndexed}, {@link TextIndexed} and {@link WildcardIndexed} on properties as well as {@link CompoundIndex}
|
||||
* and {@link WildcardIndexed} on types.
|
||||
* <p>
|
||||
* Unless specified otherwise the index name will be created out of the keys/path involved in the index. <br />
|
||||
* {@link TextIndexed} properties are collected into a single index that covers the detected fields. <br />
|
||||
* {@link java.util.Map} like structures, unless annotated with {@link WildcardIndexed}, are skipped because the
|
||||
* {@link java.util.Map.Entry#getKey() map key}, which cannot be resolved from static metadata, needs to be part of the
|
||||
* index.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Thomas Darimont
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2021 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -157,6 +157,10 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
|
||||
List<IndexDefinitionHolder> indexes, CycleGuard guard) {
|
||||
|
||||
try {
|
||||
if (isMapWithoutWildcardIndex(persistentProperty)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (persistentProperty.isEntity()) {
|
||||
indexes.addAll(resolveIndexForEntity(mappingContext.getPersistentEntity(persistentProperty),
|
||||
persistentProperty.isUnwrapped() ? "" : persistentProperty.getFieldName(), Path.of(persistentProperty),
|
||||
@@ -217,6 +221,10 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
|
||||
Path propertyPath = path.append(persistentProperty);
|
||||
guard.protect(persistentProperty, propertyPath);
|
||||
|
||||
if (isMapWithoutWildcardIndex(persistentProperty)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (persistentProperty.isEntity()) {
|
||||
try {
|
||||
indexes.addAll(resolveIndexForEntity(mappingContext.getPersistentEntity(persistentProperty),
|
||||
@@ -346,6 +354,10 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
|
||||
indexDefinitionBuilder.withLanguageOverride(persistentProperty.getFieldName());
|
||||
}
|
||||
|
||||
if (persistentProperty.isMap()) {
|
||||
return;
|
||||
}
|
||||
|
||||
TextIndexed indexed = persistentProperty.findAnnotation(TextIndexed.class);
|
||||
|
||||
if (includeOptions.isForce() || indexed != null || persistentProperty.isEntity()) {
|
||||
@@ -798,6 +810,10 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
|
||||
return expression.getValue(evaluationContext, Object.class);
|
||||
}
|
||||
|
||||
private static boolean isMapWithoutWildcardIndex(MongoPersistentProperty property) {
|
||||
return property.isMap() && !property.isAnnotationPresent(WildcardIndexed.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link CycleGuard} holds information about properties and the paths for accessing those. This information is used
|
||||
* to detect potential cycles within the references.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2021 the original author or authors.
|
||||
* Copyright 2019-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -49,13 +49,14 @@ import com.querydsl.core.types.Predicate;
|
||||
import com.querydsl.mongodb.MongodbOps;
|
||||
|
||||
/**
|
||||
* MongoDB query with utilizing {@link ReactiveMongoOperations} for command execution.
|
||||
* MongoDB query utilizing {@link ReactiveMongoOperations} for command execution.
|
||||
*
|
||||
* @implNote This class uses {@link MongoOperations} to directly convert documents into the target entity type. Also, we
|
||||
* want entites to participate in lifecycle events and entity callbacks.
|
||||
* want entities to participate in lifecycle events and entity callbacks.
|
||||
* @param <K> result type
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
* @author Rocco Lagrotteria
|
||||
* @since 2.2
|
||||
*/
|
||||
class ReactiveSpringDataMongodbQuery<K> extends SpringDataMongodbQuerySupport<ReactiveSpringDataMongodbQuery<K>> {
|
||||
@@ -96,7 +97,8 @@ class ReactiveSpringDataMongodbQuery<K> extends SpringDataMongodbQuerySupport<Re
|
||||
*/
|
||||
Mono<Page<K>> fetchPage(Pageable pageable) {
|
||||
|
||||
Mono<List<K>> content = createQuery().flatMapMany(it -> find.matching(it).all()).collectList();
|
||||
Mono<List<K>> content = createQuery().map(it -> it.with(pageable))
|
||||
.flatMapMany(it -> find.matching(it).all()).collectList();
|
||||
|
||||
return content.flatMap(it -> ReactivePageableExecutionUtils.getPage(it, pageable, fetchCount()));
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2021 the original author or authors.
|
||||
* Copyright 2021-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,11 +18,15 @@ package org.springframework.data.mongodb.util.encryption;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.bson.BsonBinary;
|
||||
import org.bson.BsonBinarySubType;
|
||||
import org.bson.types.Binary;
|
||||
import org.springframework.data.mongodb.util.spel.ExpressionUtils;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.Base64Utils;
|
||||
|
||||
/**
|
||||
* Internal utility class for dealing with encryption related matters.
|
||||
@@ -35,8 +39,8 @@ public final class EncryptionUtils {
|
||||
/**
|
||||
* Resolve a given plain {@link String} value into the store native {@literal keyId} format, considering potential
|
||||
* {@link Expression expressions}. <br />
|
||||
* The potential keyId is probed against an {@link UUID#fromString(String) UUID value} and the {@literal base64}
|
||||
* encoded {@code $binary} representation.
|
||||
* The potential keyId is probed against an {@link UUID#fromString(String) UUID value} or decoded from the
|
||||
* {@literal base64} representation prior to conversion into its {@link Binary} format.
|
||||
*
|
||||
* @param value the source value to resolve the keyId for. Must not be {@literal null}.
|
||||
* @param evaluationContext a {@link Supplier} used to provide the {@link EvaluationContext} in case an
|
||||
@@ -57,11 +61,13 @@ public final class EncryptionUtils {
|
||||
return potentialKeyId;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return UUID.fromString(potentialKeyId.toString());
|
||||
return new Binary(BsonBinarySubType.UUID_STANDARD,
|
||||
new BsonBinary(UUID.fromString(potentialKeyId.toString())).getData());
|
||||
} catch (IllegalArgumentException e) {
|
||||
return org.bson.Document.parse("{ val : { $binary : { base64 : '" + potentialKeyId + "', subType : '04'} } }")
|
||||
.get("val");
|
||||
|
||||
return new Binary(BsonBinarySubType.UUID_STANDARD, Base64Utils.decodeFromString(potentialKeyId.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2021 the original author or authors.
|
||||
* Copyright 2019-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,6 +23,7 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bson.BsonDocument;
|
||||
import org.bson.Document;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -107,7 +108,7 @@ public class MappingMongoJsonSchemaCreatorUnitTests {
|
||||
.createSchemaFor(Patient.class);
|
||||
|
||||
Document targetSchema = schema.schemaDocument();
|
||||
assertThat(targetSchema).isEqualTo(Document.parse(PATIENT));
|
||||
assertThat(targetSchema.toBsonDocument()).isEqualTo(BsonDocument.parse(PATIENT));
|
||||
}
|
||||
|
||||
@Test // GH-3800
|
||||
@@ -136,7 +137,7 @@ public class MappingMongoJsonSchemaCreatorUnitTests {
|
||||
.filter(MongoJsonSchemaCreator.encryptedOnly()) //
|
||||
.createSchemaFor(EncryptionMetadataFromProperty.class);
|
||||
|
||||
assertThat(schema.schemaDocument()).isEqualTo(Document.parse(ENC_FROM_PROPERTY_SCHEMA));
|
||||
assertThat(schema.schemaDocument().toBsonDocument()).isEqualTo(BsonDocument.parse(ENC_FROM_PROPERTY_SCHEMA));
|
||||
}
|
||||
|
||||
@Test // GH-3800
|
||||
@@ -154,7 +155,7 @@ public class MappingMongoJsonSchemaCreatorUnitTests {
|
||||
.filter(MongoJsonSchemaCreator.encryptedOnly()) //
|
||||
.createSchemaFor(EncryptionMetadataFromMethod.class);
|
||||
|
||||
assertThat(schema.schemaDocument()).isEqualTo(Document.parse(ENC_FROM_METHOD_SCHEMA));
|
||||
assertThat(schema.schemaDocument().toBsonDocument()).isEqualTo(BsonDocument.parse(ENC_FROM_METHOD_SCHEMA));
|
||||
}
|
||||
|
||||
// --> TYPES AND JSON
|
||||
@@ -392,7 +393,7 @@ public class MappingMongoJsonSchemaCreatorUnitTests {
|
||||
}
|
||||
|
||||
static final String ENC_FROM_PROPERTY_ENTITY_KEY = "C5a5aMB7Ttq4wSJTFeRn8g==";
|
||||
static final String ENC_FROM_PROPERTY_PROPOERTY_KEY = "Mw6mdTVPQfm4quqSCLVB3g=";
|
||||
static final String ENC_FROM_PROPERTY_PROPOERTY_KEY = "Mw6mdTVPQfm4quqSCLVB3g==";
|
||||
static final String ENC_FROM_PROPERTY_SCHEMA = "{" + //
|
||||
" 'encryptMetadata': {" + //
|
||||
" 'keyId': [" + //
|
||||
|
||||
@@ -27,6 +27,7 @@ import java.util.List;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
import org.springframework.data.mongodb.core.aggregation.ConditionalOperators.Cond;
|
||||
import org.springframework.data.mongodb.core.aggregation.ProjectionOperationUnitTests.BookWithFieldAnnotation;
|
||||
@@ -598,9 +599,31 @@ public class AggregationUnitTests {
|
||||
assertThat(extractPipelineElement(target, 1, "$project")).isEqualTo(Document.parse(" { \"_id\" : \"$_id\" }"));
|
||||
}
|
||||
|
||||
|
||||
@Test // GH-3898
|
||||
void shouldNotConvertIncludeExcludeValuesForProjectOperation() {
|
||||
|
||||
MongoMappingContext mappingContext = new MongoMappingContext();
|
||||
RelaxedTypeBasedAggregationOperationContext context = new RelaxedTypeBasedAggregationOperationContext(WithRetypedIdField.class, mappingContext,
|
||||
new QueryMapper(new MappingMongoConverter(NoOpDbRefResolver.INSTANCE, mappingContext)));
|
||||
Document document = project(WithRetypedIdField.class).toDocument(context);
|
||||
assertThat(document).isEqualTo(new Document("$project", new Document("_id", 1).append("renamed-field", 1)));
|
||||
}
|
||||
|
||||
private Document extractPipelineElement(Document agg, int index, String operation) {
|
||||
|
||||
List<Document> pipeline = (List<Document>) agg.get("pipeline");
|
||||
return (Document) pipeline.get(index).get(operation);
|
||||
}
|
||||
|
||||
public class WithRetypedIdField {
|
||||
|
||||
@Id
|
||||
@org.springframework.data.mongodb.core.mapping.Field
|
||||
private String id;
|
||||
|
||||
@org.springframework.data.mongodb.core.mapping.Field("renamed-field")
|
||||
private String foo;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2021 the original author or authors.
|
||||
* Copyright 2013-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -1208,7 +1208,7 @@ class UpdateMapperUnitTests {
|
||||
Document mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
|
||||
context.getPersistentEntity(EntityWithNestedMap.class));
|
||||
|
||||
assertThat(mappedUpdate).isEqualTo(new org.bson.Document("$set",new org.bson.Document("levelOne.a.b.d","e")));
|
||||
assertThat(mappedUpdate).isEqualTo(new org.bson.Document("$set", new org.bson.Document("levelOne.a.b.d", "e")));
|
||||
}
|
||||
|
||||
@Test // GH-3775
|
||||
@@ -1218,7 +1218,7 @@ class UpdateMapperUnitTests {
|
||||
Document mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
|
||||
context.getPersistentEntity(EntityWithNestedMap.class));
|
||||
|
||||
assertThat(mappedUpdate).isEqualTo(new org.bson.Document("$set",new org.bson.Document("levelOne.0.1.3","4")));
|
||||
assertThat(mappedUpdate).isEqualTo(new org.bson.Document("$set", new org.bson.Document("levelOne.0.1.3", "4")));
|
||||
}
|
||||
|
||||
@Test // GH-3775
|
||||
@@ -1228,7 +1228,7 @@ class UpdateMapperUnitTests {
|
||||
Document mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
|
||||
context.getPersistentEntity(EntityWithNestedMap.class));
|
||||
|
||||
assertThat(mappedUpdate).isEqualTo(new org.bson.Document("$set",new org.bson.Document("levelOne.0.1.c","4")));
|
||||
assertThat(mappedUpdate).isEqualTo(new org.bson.Document("$set", new org.bson.Document("levelOne.0.1.c", "4")));
|
||||
}
|
||||
|
||||
@Test // GH-3775
|
||||
@@ -1238,7 +1238,7 @@ class UpdateMapperUnitTests {
|
||||
Document mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
|
||||
context.getPersistentEntity(EntityWithNestedMap.class));
|
||||
|
||||
assertThat(mappedUpdate).isEqualTo(new org.bson.Document("$set",new org.bson.Document("levelOne.0a.1b.3c","4")));
|
||||
assertThat(mappedUpdate).isEqualTo(new org.bson.Document("$set", new org.bson.Document("levelOne.0a.1b.3c", "4")));
|
||||
}
|
||||
|
||||
@Test // GH-3688
|
||||
@@ -1262,7 +1262,7 @@ class UpdateMapperUnitTests {
|
||||
Document mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
|
||||
context.getPersistentEntity(WithDocumentReference.class));
|
||||
|
||||
assertThat(mappedUpdate).isEqualTo(new org.bson.Document("$set",new org.bson.Document("sample","s1")));
|
||||
assertThat(mappedUpdate).isEqualTo(new org.bson.Document("$set", new org.bson.Document("sample", "s1")));
|
||||
}
|
||||
|
||||
@Test // GH-3853
|
||||
@@ -1276,7 +1276,8 @@ class UpdateMapperUnitTests {
|
||||
Document mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
|
||||
context.getPersistentEntity(WithDocumentReference.class));
|
||||
|
||||
assertThat(mappedUpdate).isEqualTo(new org.bson.Document("$set",new org.bson.Document("samples",Arrays.asList("s1"))));
|
||||
assertThat(mappedUpdate)
|
||||
.isEqualTo(new org.bson.Document("$set", new org.bson.Document("samples", Arrays.asList("s1"))));
|
||||
}
|
||||
|
||||
@Test // GH-3853
|
||||
@@ -1291,7 +1292,7 @@ class UpdateMapperUnitTests {
|
||||
Document mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
|
||||
context.getPersistentEntity(WithDocumentReference.class));
|
||||
|
||||
assertThat(mappedUpdate).isEqualTo(new org.bson.Document("$set",new org.bson.Document("customer","c-name")));
|
||||
assertThat(mappedUpdate).isEqualTo(new org.bson.Document("$set", new org.bson.Document("customer", "c-name")));
|
||||
}
|
||||
|
||||
@Test // GH-3853
|
||||
@@ -1306,7 +1307,38 @@ class UpdateMapperUnitTests {
|
||||
Document mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
|
||||
context.getPersistentEntity(WithDocumentReference.class));
|
||||
|
||||
assertThat(mappedUpdate).isEqualTo(new org.bson.Document("$set",new org.bson.Document("customers", Arrays.asList("c-name"))));
|
||||
assertThat(mappedUpdate)
|
||||
.isEqualTo(new org.bson.Document("$set", new org.bson.Document("customers", Arrays.asList("c-name"))));
|
||||
}
|
||||
|
||||
@Test // GH-3921
|
||||
void mapNumericKeyInPathHavingComplexMapValyeTypes() {
|
||||
|
||||
Update update = new Update().set("testInnerData.testMap.1.intValue", "4");
|
||||
Document mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
|
||||
context.getPersistentEntity(TestData.class));
|
||||
|
||||
assertThat(mappedUpdate).isEqualTo("{ $set: { 'testInnerData.testMap.1.intValue': '4' }}");
|
||||
}
|
||||
|
||||
@Test // GH-3921
|
||||
void mapNumericKeyInPathNotMatchingExistingProperties() {
|
||||
|
||||
Update update = new Update().set("testInnerData.imaginaryMap.1.nonExistingProperty", "4");
|
||||
Document mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
|
||||
context.getPersistentEntity(TestData.class));
|
||||
|
||||
assertThat(mappedUpdate).isEqualTo("{ $set: { 'testInnerData.imaginaryMap.1.nonExistingProperty': '4' }}");
|
||||
}
|
||||
|
||||
@Test // GH-3921
|
||||
void mapNumericKeyInPathPartiallyMatchingExistingProperties() {
|
||||
|
||||
Update update = new Update().set("testInnerData.testMap.1.nonExistingProperty.2.someValue", "4");
|
||||
Document mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
|
||||
context.getPersistentEntity(TestData.class));
|
||||
|
||||
assertThat(mappedUpdate).isEqualTo("{ $set: { 'testInnerData.testMap.1.nonExistingProperty.2.someValue': '4' }}");
|
||||
}
|
||||
|
||||
static class DomainTypeWrappingConcreteyTypeHavingListOfInterfaceTypeAttributes {
|
||||
@@ -1545,7 +1577,7 @@ class UpdateMapperUnitTests {
|
||||
Map<Object, NestedDocument> concreteMap;
|
||||
}
|
||||
|
||||
static class EntityWithIntKeyedMap{
|
||||
static class EntityWithIntKeyedMap {
|
||||
Map<Integer, EntityWithObjectMap> intKeyedMap;
|
||||
}
|
||||
|
||||
@@ -1681,8 +1713,7 @@ class UpdateMapperUnitTests {
|
||||
|
||||
static class Customer {
|
||||
|
||||
@Id
|
||||
private ObjectId id;
|
||||
@Id private ObjectId id;
|
||||
private String name;
|
||||
}
|
||||
|
||||
@@ -1697,17 +1728,28 @@ class UpdateMapperUnitTests {
|
||||
|
||||
private String name;
|
||||
|
||||
@DocumentReference(lookup = "{ 'name' : ?#{#target} }")
|
||||
private Customer customer;
|
||||
@DocumentReference(lookup = "{ 'name' : ?#{#target} }") private Customer customer;
|
||||
|
||||
@DocumentReference(lookup = "{ 'name' : ?#{#target} }")
|
||||
private List<Customer> customers;
|
||||
@DocumentReference(lookup = "{ 'name' : ?#{#target} }") private List<Customer> customers;
|
||||
|
||||
@DocumentReference
|
||||
private Sample sample;
|
||||
@DocumentReference private Sample sample;
|
||||
|
||||
@DocumentReference
|
||||
private List<Sample> samples;
|
||||
@DocumentReference private List<Sample> samples;
|
||||
}
|
||||
|
||||
@Data
|
||||
private static class TestData {
|
||||
@Id private String id;
|
||||
private TestInnerData testInnerData;
|
||||
}
|
||||
|
||||
@Data
|
||||
private static class TestInnerData {
|
||||
private Map<Integer, TestValue> testMap;
|
||||
}
|
||||
|
||||
@Data
|
||||
private static class TestValue {
|
||||
private int intValue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2021 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -319,7 +319,8 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
|
||||
class IndexOnLevelZeroWithExplicityNamedField {
|
||||
|
||||
@Indexed @Field("customFieldName") String namedProperty;
|
||||
@Indexed
|
||||
@Field("customFieldName") String namedProperty;
|
||||
}
|
||||
|
||||
@Document
|
||||
@@ -427,7 +428,8 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
|
||||
@Document
|
||||
class IndexOnMetaAnnotatedField {
|
||||
@Field("_name") @IndexedFieldAnnotation String lastname;
|
||||
@Field("_name")
|
||||
@IndexedFieldAnnotation String lastname;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1366,10 +1368,9 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
});
|
||||
assertThat(indices.get(2)).satisfies(it -> {
|
||||
assertThat(it.getIndexKeys()).containsEntry("withOptions.$**", 1);
|
||||
assertThat(it.getIndexOptions()).containsEntry("name",
|
||||
"withOptions.idx")
|
||||
.containsEntry("collation", new org.bson.Document("locale", "en_US"))
|
||||
.containsEntry("partialFilterExpression", new org.bson.Document("$eq", 1));
|
||||
assertThat(it.getIndexOptions()).containsEntry("name", "withOptions.idx")
|
||||
.containsEntry("collation", new org.bson.Document("locale", "en_US"))
|
||||
.containsEntry("partialFilterExpression", new org.bson.Document("$eq", 1));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1393,6 +1394,15 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test // GH-3914
|
||||
public void shouldSkipMapStructuresUnlessAnnotatedWithWildcardIndex() {
|
||||
|
||||
List<IndexDefinitionHolder> indexDefinitions = prepareMappingContextAndResolveIndexForType(
|
||||
WithMapStructures.class);
|
||||
|
||||
assertThat(indexDefinitions).hasSize(1);
|
||||
}
|
||||
|
||||
@Document
|
||||
class MixedIndexRoot {
|
||||
|
||||
@@ -1482,7 +1492,8 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
@Document
|
||||
class SimilarityHolingBean {
|
||||
|
||||
@Indexed @Field("norm") String normalProperty;
|
||||
@Indexed
|
||||
@Field("norm") String normalProperty;
|
||||
@Field("similarityL") private List<SimilaritySibling> listOfSimilarilyNamedEntities = null;
|
||||
}
|
||||
|
||||
@@ -1626,6 +1637,17 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
T entity;
|
||||
}
|
||||
|
||||
@Document
|
||||
class WithMapStructures {
|
||||
Map<String, ValueObject> rootMap;
|
||||
NestedInMapWithStructures nested;
|
||||
ValueObject plainValue;
|
||||
}
|
||||
|
||||
class NestedInMapWithStructures {
|
||||
Map<String, ValueObject> nestedMap;
|
||||
}
|
||||
|
||||
@Document
|
||||
class EntityWithGenericTypeWrapperAsElement {
|
||||
List<GenericEntityWrapper<DocumentWithNamedIndex>> listWithGeneircTypeElement;
|
||||
@@ -1634,7 +1656,8 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
@Document
|
||||
class WithHashedIndexOnId {
|
||||
|
||||
@HashIndexed @Id String id;
|
||||
@HashIndexed
|
||||
@Id String id;
|
||||
}
|
||||
|
||||
@Document
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2021 the original author or authors.
|
||||
* Copyright 2019-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -65,6 +65,7 @@ import com.mongodb.reactivestreams.client.MongoDatabase;
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
* @author Rocco Lagrotteria
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration
|
||||
@@ -401,7 +402,7 @@ public class ReactiveQuerydslMongoPredicateExecutorTests {
|
||||
.assertNext(it -> {
|
||||
|
||||
assertThat(it.getTotalElements()).isEqualTo(2);
|
||||
assertThat(it.getContent()).contains(dave);
|
||||
assertThat(it.getContent()).containsOnly(dave);
|
||||
}).verifyComplete();
|
||||
|
||||
repository
|
||||
@@ -410,7 +411,7 @@ public class ReactiveQuerydslMongoPredicateExecutorTests {
|
||||
.assertNext(it -> {
|
||||
|
||||
assertThat(it.getTotalElements()).isEqualTo(2);
|
||||
assertThat(it.getContent()).contains(oliver);
|
||||
assertThat(it.getContent()).containsOnly(oliver);
|
||||
}).verifyComplete();
|
||||
}
|
||||
|
||||
|
||||
@@ -402,12 +402,17 @@ Indexes are automatically created for the initial entity set on application star
|
||||
|
||||
We generally recommend explicit index creation for application-based control of indexes as Spring Data cannot automatically create indexes for collections that were recreated while the application was running.
|
||||
|
||||
`IndexResolver` provides an abstraction for programmatic index definition creation if you want to make use of `@Indexed` annotations such as `@GeoSpatialIndexed`, `@TextIndexed`, `@CompoundIndex`.
|
||||
`IndexResolver` provides an abstraction for programmatic index definition creation if you want to make use of `@Indexed` annotations such as `@GeoSpatialIndexed`, `@TextIndexed`, `@CompoundIndex` and `@WildcardIndexed`.
|
||||
You can use index definitions with `IndexOperations` to create indexes.
|
||||
A good point in time for index creation is on application startup, specifically after the application context was refreshed, triggered by observing `ContextRefreshedEvent`.
|
||||
This event guarantees that the context is fully initialized.
|
||||
Note that at this time other components, especially bean factories might have access to the MongoDB database.
|
||||
|
||||
[WARNING]
|
||||
====
|
||||
``Map``-like properties are skipped by the `IndexResolver` unless annotated with `@WildcardIndexed` because the _map key_ must be part of the index definition. Since the purpose of maps is the usage of dynamic keys and values, the keys cannot be resolved from static mapping metadata.
|
||||
====
|
||||
|
||||
.Programmatic Index Creation for a single Domain Type
|
||||
====
|
||||
[source,java]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Spring Data MongoDB 3.3 GA (2021.1.0)
|
||||
Spring Data MongoDB 3.3.1 (2021.1.1)
|
||||
Copyright (c) [2010-2019] Pivotal Software, Inc.
|
||||
|
||||
This product is licensed to you under the Apache License, Version 2.0 (the "License").
|
||||
@@ -30,5 +30,6 @@ conditions of the subcomponent's license, as noted in the LICENSE file.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user