diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolver.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolver.java index 6881f658e..87c637739 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolver.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolver.java @@ -220,7 +220,7 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver { } private void appendTextIndexInformation(final String dotPath, - final TextIndexDefinitionBuilder indexDefinitionBuilder, MongoPersistentEntity entity, + final TextIndexDefinitionBuilder indexDefinitionBuilder, final MongoPersistentEntity entity, final TextIndexIncludeOptions includeOptions, final CycleGuard guard) { entity.doWithProperties(new PropertyHandler() { @@ -230,7 +230,7 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver { guard.protect(persistentProperty, dotPath); - if (persistentProperty.isLanguageProperty()) { + if (persistentProperty.isExplicitLanguageProperty() && !StringUtils.hasText(dotPath)) { indexDefinitionBuilder.withLanguageOverride(persistentProperty.getFieldName()); } @@ -257,6 +257,10 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver { mappingContext.getPersistentEntity(persistentProperty.getActualType()), optionsForNestedType, guard); } catch (CyclicPropertyReferenceException e) { LOGGER.warn(e.getMessage(), e); + } catch (InvalidDataAccessApiUsageException e) { + LOGGER.warn( + String.format("Potentially invald index structure discovered. Breaking operation for %s.", + entity.getName()), e); } } else if (includeOptions.isForce() || indexed != null) { indexDefinitionBuilder.onField(propertyDotPath, weight); diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentProperty.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentProperty.java index bd2aab0eb..bde3c63bd 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentProperty.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentProperty.java @@ -190,9 +190,18 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope */ @Override public boolean isLanguageProperty() { - return getFieldName().equals(LANGUAGE_FIELD_NAME) || isAnnotationPresent(Language.class); + return getFieldName().equals(LANGUAGE_FIELD_NAME) || isExplicitLanguageProperty(); } + /* + * (non-Javadoc) + * @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#isExplicitLanguageProperty() + */ + @Override + public boolean isExplicitLanguageProperty() { + return isAnnotationPresent(Language.class); + }; + /* * (non-Javadoc) * @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#isTextScoreProperty() diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoPersistentProperty.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoPersistentProperty.java index 7887a1586..80fd2a55d 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoPersistentProperty.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoPersistentProperty.java @@ -61,14 +61,22 @@ public interface MongoPersistentProperty extends PersistentProperty * It's marked with {@link TextScore}. diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolverUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolverUnitTests.java index 48f14d99f..5df5d5391 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolverUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolverUnitTests.java @@ -15,10 +15,7 @@ */ package org.springframework.data.mongodb.core.index; -import static org.hamcrest.collection.IsCollectionWithSize.*; -import static org.hamcrest.collection.IsEmptyCollection.*; -import static org.hamcrest.core.IsEqual.*; -import static org.hamcrest.core.IsInstanceOf.*; +import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import static org.mockito.Mockito.*; @@ -26,8 +23,6 @@ import java.lang.annotation.Annotation; import java.util.Collections; import java.util.List; -import org.hamcrest.collection.IsEmptyCollection; -import org.hamcrest.core.IsEqual; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Suite; @@ -461,7 +456,7 @@ public class MongoPersistentEntityIndexResolverUnitTests { indexDefinitions.get(0)); DBObject weights = DBObjectTestUtils.getAsDBObject(indexDefinitions.get(0).getIndexOptions(), "weights"); - assertThat(weights.get("nested.foo"), IsEqual. equalTo(5F)); + assertThat(weights.get("nested.foo"), is((Object) 5F)); } /** @@ -476,8 +471,8 @@ public class MongoPersistentEntityIndexResolverUnitTests { "textIndexOnNestedWithMostSpecificValueRoot", indexDefinitions.get(0)); DBObject weights = DBObjectTestUtils.getAsDBObject(indexDefinitions.get(0).getIndexOptions(), "weights"); - assertThat(weights.get("nested.foo"), IsEqual. equalTo(5F)); - assertThat(weights.get("nested.bar"), IsEqual. equalTo(10F)); + assertThat(weights.get("nested.foo"), is((Object) 5F)); + assertThat(weights.get("nested.bar"), is((Object) 10F)); } /** @@ -487,17 +482,57 @@ public class MongoPersistentEntityIndexResolverUnitTests { public void shouldSetDefaultLanguageCorrectly() { List indexDefinitions = prepareMappingContextAndResolveIndexForType(DocumentWithDefaultLanguage.class); - assertThat(indexDefinitions.get(0).getIndexOptions().get("default_language"), IsEqual. equalTo("spanish")); + assertThat(indexDefinitions.get(0).getIndexOptions().get("default_language"), is((Object) "spanish")); } /** - * @see DATAMONGO-937 + * @see DATAMONGO-937, DATAMONGO-1049 */ @Test public void shouldResolveTextIndexLanguageOverrideCorrectly() { - List indexDefinitions = prepareMappingContextAndResolveIndexForType(DocumentWithLanguageOverrideOnNestedElementRoot.class); - assertThat(indexDefinitions.get(0).getIndexOptions().get("language_override"), IsEqual. equalTo("lang")); + List indexDefinitions = prepareMappingContextAndResolveIndexForType(DocumentWithLanguageOverride.class); + assertThat(indexDefinitions.get(0).getIndexOptions().get("language_override"), is((Object) "lang")); + } + + /** + * @see DATAMONGO-1049 + */ + @Test + public void shouldIgnoreTextIndexLanguageOverrideOnNestedElements() { + + List indexDefinitions = prepareMappingContextAndResolveIndexForType(DocumentWithLanguageOverrideOnNestedElement.class); + assertThat(indexDefinitions.get(0).getIndexOptions().get("language_override"), is(nullValue())); + } + + /** + * @see DATAMONGO-1049 + */ + @Test + public void shouldNotCreateIndexDefinitionWhenOnlyLanguageButNoTextIndexPresent() { + + List indexDefinitions = prepareMappingContextAndResolveIndexForType(DocumentWithNoTextIndexPropertyButReservedFieldLanguage.class); + assertThat(indexDefinitions, is(empty())); + } + + /** + * @see DATAMONGO-1049 + */ + @Test + public void shouldNotCreateIndexDefinitionWhenOnlyAnnotatedLanguageButNoTextIndexPresent() { + + List indexDefinitions = prepareMappingContextAndResolveIndexForType(DocumentWithNoTextIndexPropertyButReservedFieldLanguageAnnotated.class); + assertThat(indexDefinitions, is(empty())); + } + + /** + * @see DATAMONGO-1049 + */ + @Test + public void shouldPreferExplicitlyAnnotatedLanguageProperty() { + + List indexDefinitions = prepareMappingContextAndResolveIndexForType(DocumentWithOverlappingLanguageProps.class); + assertThat(indexDefinitions.get(0).getIndexOptions().get("language_override"), is((Object) "lang")); } @Document @@ -527,14 +562,12 @@ public class MongoPersistentEntityIndexResolverUnitTests { static class TextIndexOnNested { String foo; - } @Document static class TextIndexOnNestedWithWeightRoot { @TextIndexed(weight = 5) TextIndexOnNested nested; - } @Document @@ -554,18 +587,39 @@ public class MongoPersistentEntityIndexResolverUnitTests { } @Document - static class DocumentWithLanguageOverrideOnNestedElementRoot { + static class DocumentWithLanguageOverrideOnNestedElement { - DocumentWithLanguageOverrideOnNestedElement nested; + DocumentWithLanguageOverride nested; } - static class DocumentWithLanguageOverrideOnNestedElement { + @Document + static class DocumentWithLanguageOverride { @TextIndexed String foo; @Language String lang; } + @Document + static class DocumentWithNoTextIndexPropertyButReservedFieldLanguage { + + String language; + } + + @Document + static class DocumentWithNoTextIndexPropertyButReservedFieldLanguageAnnotated { + + @Field("language") String lang; + } + + @Document + static class DocumentWithOverlappingLanguageProps { + + @TextIndexed String foo; + String language; + @Language String lang; + } + } public static class MixedIndexResolutionTests { @@ -670,7 +724,7 @@ public class MongoPersistentEntityIndexResolverUnitTests { public void shouldDetectSelfCycleViaCollectionTypeCorrectly() { List indexDefinitions = prepareMappingContextAndResolveIndexForType(SelfCyclingViaCollectionType.class); - assertThat(indexDefinitions, IsEmptyCollection.empty()); + assertThat(indexDefinitions, empty()); } /** @@ -680,7 +734,7 @@ public class MongoPersistentEntityIndexResolverUnitTests { public void shouldNotDetectCycleWhenTypeIsUsedMoreThanOnce() { List indexDefinitions = prepareMappingContextAndResolveIndexForType(MultipleObjectsOfSameType.class); - assertThat(indexDefinitions, IsEmptyCollection.empty()); + assertThat(indexDefinitions, empty()); } /**