Skip to content

Commit 7dd3450

Browse files
christophstroblodrotbohm
authored andcommitted
DATAMONGO-1049 - Check for explicitly declared language field.
We now check for an explicitly declared language field for setting language_override within a text index. Therefore the attribute (even if named with the reserved keyword language) has to be explicitly marked with @language. Prior to this change having: @language String lang; String language; would have caused trouble when trying to resolve index structures as one cannot set language override to more than one property. Original pull request: #224.
1 parent ca4b2a6 commit 7dd3450

File tree

4 files changed

+100
-25
lines changed

4 files changed

+100
-25
lines changed

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolver.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ private Collection<? extends IndexDefinitionHolder> potentiallyCreateTextIndexDe
220220
}
221221

222222
private void appendTextIndexInformation(final String dotPath,
223-
final TextIndexDefinitionBuilder indexDefinitionBuilder, MongoPersistentEntity<?> entity,
223+
final TextIndexDefinitionBuilder indexDefinitionBuilder, final MongoPersistentEntity<?> entity,
224224
final TextIndexIncludeOptions includeOptions, final CycleGuard guard) {
225225

226226
entity.doWithProperties(new PropertyHandler<MongoPersistentProperty>() {
@@ -230,7 +230,7 @@ public void doWithPersistentProperty(MongoPersistentProperty persistentProperty)
230230

231231
guard.protect(persistentProperty, dotPath);
232232

233-
if (persistentProperty.isLanguageProperty()) {
233+
if (persistentProperty.isExplicitLanguageProperty() && !StringUtils.hasText(dotPath)) {
234234
indexDefinitionBuilder.withLanguageOverride(persistentProperty.getFieldName());
235235
}
236236

@@ -257,6 +257,10 @@ public void doWithPersistentProperty(MongoPersistentProperty persistentProperty)
257257
mappingContext.getPersistentEntity(persistentProperty.getActualType()), optionsForNestedType, guard);
258258
} catch (CyclicPropertyReferenceException e) {
259259
LOGGER.warn(e.getMessage(), e);
260+
} catch (InvalidDataAccessApiUsageException e) {
261+
LOGGER.warn(
262+
String.format("Potentially invald index structure discovered. Breaking operation for %s.",
263+
entity.getName()), e);
260264
}
261265
} else if (includeOptions.isForce() || indexed != null) {
262266
indexDefinitionBuilder.onField(propertyDotPath, weight);

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentProperty.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,9 +190,18 @@ public DBRef getDBRef() {
190190
*/
191191
@Override
192192
public boolean isLanguageProperty() {
193-
return getFieldName().equals(LANGUAGE_FIELD_NAME) || isAnnotationPresent(Language.class);
193+
return getFieldName().equals(LANGUAGE_FIELD_NAME) || isExplicitLanguageProperty();
194194
}
195195

196+
/*
197+
* (non-Javadoc)
198+
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#isExplicitLanguageProperty()
199+
*/
200+
@Override
201+
public boolean isExplicitLanguageProperty() {
202+
return isAnnotationPresent(Language.class);
203+
};
204+
196205
/*
197206
* (non-Javadoc)
198207
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#isTextScoreProperty()

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoPersistentProperty.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,22 @@ public interface MongoPersistentProperty extends PersistentProperty<MongoPersist
6161
boolean isExplicitIdProperty();
6262

6363
/**
64-
* Returns whether the property indicates the documents language either by having a {@link #getFieldName()} equal to
65-
* {@literal language} or being annotated with {@link Language}.
64+
* Returns true whether the property indicates the documents language either by having a {@link #getFieldName()} equal
65+
* to {@literal language} or being annotated with {@link Language}.
6666
*
6767
* @return
6868
* @since 1.6
6969
*/
7070
boolean isLanguageProperty();
7171

72+
/**
73+
* Returns true when property being annotated with {@link Language}.
74+
*
75+
* @return
76+
* @since 1.6.1
77+
*/
78+
boolean isExplicitLanguageProperty();
79+
7280
/**
7381
* Returns whether the property holds the documents score calculated by text search. <br/>
7482
* It's marked with {@link TextScore}.

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolverUnitTests.java

Lines changed: 74 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,14 @@
1515
*/
1616
package org.springframework.data.mongodb.core.index;
1717

18-
import static org.hamcrest.collection.IsCollectionWithSize.*;
19-
import static org.hamcrest.collection.IsEmptyCollection.*;
20-
import static org.hamcrest.core.IsEqual.*;
21-
import static org.hamcrest.core.IsInstanceOf.*;
18+
import static org.hamcrest.Matchers.*;
2219
import static org.junit.Assert.*;
2320
import static org.mockito.Mockito.*;
2421

2522
import java.lang.annotation.Annotation;
2623
import java.util.Collections;
2724
import java.util.List;
2825

29-
import org.hamcrest.collection.IsEmptyCollection;
30-
import org.hamcrest.core.IsEqual;
3126
import org.junit.Test;
3227
import org.junit.runner.RunWith;
3328
import org.junit.runners.Suite;
@@ -461,7 +456,7 @@ public void shouldResolveTextIndexOnElementWithWeightCorrectly() {
461456
indexDefinitions.get(0));
462457

463458
DBObject weights = DBObjectTestUtils.getAsDBObject(indexDefinitions.get(0).getIndexOptions(), "weights");
464-
assertThat(weights.get("nested.foo"), IsEqual.<Object> equalTo(5F));
459+
assertThat(weights.get("nested.foo"), is((Object) 5F));
465460
}
466461

467462
/**
@@ -476,8 +471,8 @@ public void shouldResolveTextIndexOnElementWithMostSpecificWeightCorrectly() {
476471
"textIndexOnNestedWithMostSpecificValueRoot", indexDefinitions.get(0));
477472

478473
DBObject weights = DBObjectTestUtils.getAsDBObject(indexDefinitions.get(0).getIndexOptions(), "weights");
479-
assertThat(weights.get("nested.foo"), IsEqual.<Object> equalTo(5F));
480-
assertThat(weights.get("nested.bar"), IsEqual.<Object> equalTo(10F));
474+
assertThat(weights.get("nested.foo"), is((Object) 5F));
475+
assertThat(weights.get("nested.bar"), is((Object) 10F));
481476
}
482477

483478
/**
@@ -487,17 +482,57 @@ public void shouldResolveTextIndexOnElementWithMostSpecificWeightCorrectly() {
487482
public void shouldSetDefaultLanguageCorrectly() {
488483

489484
List<IndexDefinitionHolder> indexDefinitions = prepareMappingContextAndResolveIndexForType(DocumentWithDefaultLanguage.class);
490-
assertThat(indexDefinitions.get(0).getIndexOptions().get("default_language"), IsEqual.<Object> equalTo("spanish"));
485+
assertThat(indexDefinitions.get(0).getIndexOptions().get("default_language"), is((Object) "spanish"));
491486
}
492487

493488
/**
494-
* @see DATAMONGO-937
489+
* @see DATAMONGO-937, DATAMONGO-1049
495490
*/
496491
@Test
497492
public void shouldResolveTextIndexLanguageOverrideCorrectly() {
498493

499-
List<IndexDefinitionHolder> indexDefinitions = prepareMappingContextAndResolveIndexForType(DocumentWithLanguageOverrideOnNestedElementRoot.class);
500-
assertThat(indexDefinitions.get(0).getIndexOptions().get("language_override"), IsEqual.<Object> equalTo("lang"));
494+
List<IndexDefinitionHolder> indexDefinitions = prepareMappingContextAndResolveIndexForType(DocumentWithLanguageOverride.class);
495+
assertThat(indexDefinitions.get(0).getIndexOptions().get("language_override"), is((Object) "lang"));
496+
}
497+
498+
/**
499+
* @see DATAMONGO-1049
500+
*/
501+
@Test
502+
public void shouldIgnoreTextIndexLanguageOverrideOnNestedElements() {
503+
504+
List<IndexDefinitionHolder> indexDefinitions = prepareMappingContextAndResolveIndexForType(DocumentWithLanguageOverrideOnNestedElement.class);
505+
assertThat(indexDefinitions.get(0).getIndexOptions().get("language_override"), is(nullValue()));
506+
}
507+
508+
/**
509+
* @see DATAMONGO-1049
510+
*/
511+
@Test
512+
public void shouldNotCreateIndexDefinitionWhenOnlyLanguageButNoTextIndexPresent() {
513+
514+
List<IndexDefinitionHolder> indexDefinitions = prepareMappingContextAndResolveIndexForType(DocumentWithNoTextIndexPropertyButReservedFieldLanguage.class);
515+
assertThat(indexDefinitions, is(empty()));
516+
}
517+
518+
/**
519+
* @see DATAMONGO-1049
520+
*/
521+
@Test
522+
public void shouldNotCreateIndexDefinitionWhenOnlyAnnotatedLanguageButNoTextIndexPresent() {
523+
524+
List<IndexDefinitionHolder> indexDefinitions = prepareMappingContextAndResolveIndexForType(DocumentWithNoTextIndexPropertyButReservedFieldLanguageAnnotated.class);
525+
assertThat(indexDefinitions, is(empty()));
526+
}
527+
528+
/**
529+
* @see DATAMONGO-1049
530+
*/
531+
@Test
532+
public void shouldPreferExplicitlyAnnotatedLanguageProperty() {
533+
534+
List<IndexDefinitionHolder> indexDefinitions = prepareMappingContextAndResolveIndexForType(DocumentWithOverlappingLanguageProps.class);
535+
assertThat(indexDefinitions.get(0).getIndexOptions().get("language_override"), is((Object) "lang"));
501536
}
502537

503538
@Document
@@ -527,14 +562,12 @@ static class TextIndexOnNestedRoot {
527562
static class TextIndexOnNested {
528563

529564
String foo;
530-
531565
}
532566

533567
@Document
534568
static class TextIndexOnNestedWithWeightRoot {
535569

536570
@TextIndexed(weight = 5) TextIndexOnNested nested;
537-
538571
}
539572

540573
@Document
@@ -554,18 +587,39 @@ static class DocumentWithDefaultLanguage {
554587
}
555588

556589
@Document
557-
static class DocumentWithLanguageOverrideOnNestedElementRoot {
590+
static class DocumentWithLanguageOverrideOnNestedElement {
558591

559-
DocumentWithLanguageOverrideOnNestedElement nested;
592+
DocumentWithLanguageOverride nested;
560593
}
561594

562-
static class DocumentWithLanguageOverrideOnNestedElement {
595+
@Document
596+
static class DocumentWithLanguageOverride {
563597

564598
@TextIndexed String foo;
565599

566600
@Language String lang;
567601
}
568602

603+
@Document
604+
static class DocumentWithNoTextIndexPropertyButReservedFieldLanguage {
605+
606+
String language;
607+
}
608+
609+
@Document
610+
static class DocumentWithNoTextIndexPropertyButReservedFieldLanguageAnnotated {
611+
612+
@Field("language") String lang;
613+
}
614+
615+
@Document
616+
static class DocumentWithOverlappingLanguageProps {
617+
618+
@TextIndexed String foo;
619+
String language;
620+
@Language String lang;
621+
}
622+
569623
}
570624

571625
public static class MixedIndexResolutionTests {
@@ -670,7 +724,7 @@ public void shouldNotDetectCycleInSimilarlyNamedProperties() {
670724
public void shouldDetectSelfCycleViaCollectionTypeCorrectly() {
671725

672726
List<IndexDefinitionHolder> indexDefinitions = prepareMappingContextAndResolveIndexForType(SelfCyclingViaCollectionType.class);
673-
assertThat(indexDefinitions, IsEmptyCollection.empty());
727+
assertThat(indexDefinitions, empty());
674728
}
675729

676730
/**
@@ -680,7 +734,7 @@ public void shouldDetectSelfCycleViaCollectionTypeCorrectly() {
680734
public void shouldNotDetectCycleWhenTypeIsUsedMoreThanOnce() {
681735

682736
List<IndexDefinitionHolder> indexDefinitions = prepareMappingContextAndResolveIndexForType(MultipleObjectsOfSameType.class);
683-
assertThat(indexDefinitions, IsEmptyCollection.empty());
737+
assertThat(indexDefinitions, empty());
684738
}
685739

686740
/**

0 commit comments

Comments
 (0)