Avoid creating invalid index definitions for Map-like properties.
This commit makes sure to exclude Map like structures from index inspection unless annotated with WilcardIndexed. Closes #3914, closes #3901 Original pull request: #3915.
This commit is contained in:
committed by
Mark Paluch
parent
9c78802c47
commit
e0a57fa19b
@@ -25,6 +25,15 @@ 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
|
||||
|
||||
@@ -158,6 +158,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),
|
||||
@@ -220,6 +224,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),
|
||||
@@ -349,6 +357,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()) {
|
||||
@@ -801,6 +813,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.
|
||||
|
||||
@@ -1393,6 +1393,15 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test // GH-3914
|
||||
public void shouldSkipMapStructuresUnlessAnnotatedWithWildcardIndex() {
|
||||
|
||||
List<IndexDefinitionHolder> indexDefinitions = prepareMappingContextAndResolveIndexForType(
|
||||
WithMapStructures.class);
|
||||
|
||||
assertThat(indexDefinitions).hasSize(1);
|
||||
}
|
||||
|
||||
@Document
|
||||
class MixedIndexRoot {
|
||||
|
||||
@@ -1626,6 +1635,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;
|
||||
|
||||
@@ -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 structures, unless annotated with `@WildcardIndexed`, are skipped by the `IndexResolver` because the _map key_, which cannot be resolved from static metadata, needs to be part of the index definition.
|
||||
===
|
||||
|
||||
.Programmatic Index Creation for a single Domain Type
|
||||
====
|
||||
[source,java]
|
||||
|
||||
Reference in New Issue
Block a user