4646import org .springframework .data .mongodb .core .mapping .Document ;
4747import org .springframework .data .mongodb .core .mapping .MongoPersistentEntity ;
4848import org .springframework .data .mongodb .core .mapping .MongoPersistentProperty ;
49+ import org .springframework .data .mongodb .core .query .Collation ;
4950import org .springframework .data .mongodb .util .BsonUtils ;
5051import org .springframework .data .mongodb .util .DotPath ;
5152import org .springframework .data .spel .EvaluationContextProvider ;
@@ -121,6 +122,7 @@ public List<IndexDefinitionHolder> resolveIndexForEntity(MongoPersistentEntity<?
121122 List <IndexDefinitionHolder > indexInformation = new ArrayList <>();
122123 String collection = root .getCollection ();
123124 indexInformation .addAll (potentiallyCreateCompoundIndexDefinitions ("" , collection , root ));
125+ indexInformation .addAll (potentiallyCreateWildcardIndexDefinitions ("" , collection , root ));
124126 indexInformation .addAll (potentiallyCreateTextIndexDefinition (root , collection ));
125127
126128 root .doWithProperties ((PropertyHandler <MongoPersistentProperty >) property -> this
@@ -162,17 +164,18 @@ private void potentiallyAddIndexForProperty(MongoPersistentEntity<?> root, Mongo
162164 * @return List of {@link IndexDefinitionHolder} representing indexes for given type and its referenced property
163165 * types. Will never be {@code null}.
164166 */
165- private List <IndexDefinitionHolder > resolveIndexForClass ( TypeInformation <?> type , String dotPath ,
166- Path path , String collection , CycleGuard guard ) {
167+ private List <IndexDefinitionHolder > resolveIndexForClass (TypeInformation <?> type , String dotPath , Path path ,
168+ String collection , CycleGuard guard ) {
167169
168170 return resolveIndexForEntity (mappingContext .getRequiredPersistentEntity (type ), dotPath , path , collection , guard );
169171 }
170172
171- private List <IndexDefinitionHolder > resolveIndexForEntity (MongoPersistentEntity <?> entity , String dotPath ,
172- Path path , String collection , CycleGuard guard ) {
173+ private List <IndexDefinitionHolder > resolveIndexForEntity (MongoPersistentEntity <?> entity , String dotPath , Path path ,
174+ String collection , CycleGuard guard ) {
173175
174176 List <IndexDefinitionHolder > indexInformation = new ArrayList <>();
175177 indexInformation .addAll (potentiallyCreateCompoundIndexDefinitions (dotPath , collection , entity ));
178+ indexInformation .addAll (potentiallyCreateWildcardIndexDefinitions (dotPath , collection , entity ));
176179
177180 entity .doWithProperties ((PropertyHandler <MongoPersistentProperty >) property -> this
178181 .guardAndPotentiallyAddIndexForProperty (property , dotPath , path , collection , indexInformation , guard ));
@@ -196,15 +199,15 @@ private void guardAndPotentiallyAddIndexForProperty(MongoPersistentProperty pers
196199
197200 if (persistentProperty .isEntity ()) {
198201 try {
199- indexes .addAll (resolveIndexForEntity (mappingContext .getPersistentEntity (persistentProperty ), propertyDotPath . toString (),
200- propertyPath , collection , guard ));
202+ indexes .addAll (resolveIndexForEntity (mappingContext .getPersistentEntity (persistentProperty ),
203+ propertyDotPath . toString (), propertyPath , collection , guard ));
201204 } catch (CyclicPropertyReferenceException e ) {
202205 LOGGER .info (e .getMessage ());
203206 }
204207 }
205208
206- List <IndexDefinitionHolder > indexDefinitions = createIndexDefinitionHolderForProperty (propertyDotPath .toString (), collection ,
207- persistentProperty );
209+ List <IndexDefinitionHolder > indexDefinitions = createIndexDefinitionHolderForProperty (propertyDotPath .toString (),
210+ collection , persistentProperty );
208211
209212 if (!indexDefinitions .isEmpty ()) {
210213 indexes .addAll (indexDefinitions );
@@ -232,6 +235,11 @@ private List<IndexDefinitionHolder> createIndexDefinitionHolderForProperty(Strin
232235 if (persistentProperty .isAnnotationPresent (HashIndexed .class )) {
233236 indices .add (createHashedIndexDefinition (dotPath , collection , persistentProperty ));
234237 }
238+ if (persistentProperty .isAnnotationPresent (WildcardIndexed .class )) {
239+ indices .add (createWildcardIndexDefinition (dotPath , collection ,
240+ persistentProperty .getRequiredAnnotation (WildcardIndexed .class ),
241+ mappingContext .getPersistentEntity (persistentProperty )));
242+ }
235243
236244 return indices ;
237245 }
@@ -246,6 +254,18 @@ private List<IndexDefinitionHolder> potentiallyCreateCompoundIndexDefinitions(St
246254 return createCompoundIndexDefinitions (dotPath , collection , entity );
247255 }
248256
257+ private List <IndexDefinitionHolder > potentiallyCreateWildcardIndexDefinitions (String dotPath , String collection ,
258+ MongoPersistentEntity <?> entity ) {
259+
260+ if (entity .findAnnotation (WildcardIndexed .class ) == null ) {
261+ return Collections .emptyList ();
262+ }
263+
264+ return Collections .singletonList (new IndexDefinitionHolder (dotPath ,
265+ createWildcardIndexDefinition (dotPath , collection , entity .getRequiredAnnotation (WildcardIndexed .class ), entity ),
266+ collection ));
267+ }
268+
249269 private Collection <? extends IndexDefinitionHolder > potentiallyCreateTextIndexDefinition (
250270 MongoPersistentEntity <?> root , String collection ) {
251271
@@ -292,9 +312,8 @@ private Collection<? extends IndexDefinitionHolder> potentiallyCreateTextIndexDe
292312
293313 }
294314
295- private void appendTextIndexInformation (DotPath dotPath , Path path ,
296- TextIndexDefinitionBuilder indexDefinitionBuilder , MongoPersistentEntity <?> entity ,
297- TextIndexIncludeOptions includeOptions , CycleGuard guard ) {
315+ private void appendTextIndexInformation (DotPath dotPath , Path path , TextIndexDefinitionBuilder indexDefinitionBuilder ,
316+ MongoPersistentEntity <?> entity , TextIndexIncludeOptions includeOptions , CycleGuard guard ) {
298317
299318 entity .doWithProperties (new PropertyHandler <MongoPersistentProperty >() {
300319
@@ -311,8 +330,7 @@ public void doWithPersistentProperty(MongoPersistentProperty persistentProperty)
311330
312331 if (includeOptions .isForce () || indexed != null || persistentProperty .isEntity ()) {
313332
314- DotPath propertyDotPath = dotPath
315- .append (persistentProperty .getFieldName ());
333+ DotPath propertyDotPath = dotPath .append (persistentProperty .getFieldName ());
316334
317335 Path propertyPath = path .append (persistentProperty );
318336
@@ -406,6 +424,32 @@ protected IndexDefinitionHolder createCompoundIndexDefinition(String dotPath, St
406424 return new IndexDefinitionHolder (dotPath , indexDefinition , collection );
407425 }
408426
427+ protected IndexDefinitionHolder createWildcardIndexDefinition (String dotPath , String collection ,
428+ WildcardIndexed index , @ Nullable MongoPersistentEntity <?> entity ) {
429+
430+ WildcardIndex indexDefinition = new WildcardIndex (dotPath );
431+
432+ if (StringUtils .hasText (index .wildcardProjection ())) {
433+ indexDefinition .wildcardProjection (evaluateWildcardProjection (index .wildcardProjection (), entity ));
434+ }
435+
436+ if (!index .useGeneratedName ()) {
437+ indexDefinition .named (pathAwareIndexName (index .name (), dotPath , entity , null ));
438+ }
439+
440+ if (StringUtils .hasText (index .partialFilter ())) {
441+ indexDefinition .partial (evaluatePartialFilter (index .partialFilter (), entity ));
442+ }
443+
444+ if (StringUtils .hasText (index .collation ())) {
445+ indexDefinition .collation (evaluateCollation (index .collation (), entity ));
446+ } else if (entity != null && entity .hasCollation ()) {
447+ indexDefinition .collation (entity .getCollation ());
448+ }
449+
450+ return new IndexDefinitionHolder (dotPath , indexDefinition , collection );
451+ }
452+
409453 private org .bson .Document resolveCompoundIndexKeyFromStringDefinition (String dotPath , String keyDefinitionString ,
410454 PersistentEntity <?, ?> entity ) {
411455
@@ -510,6 +554,33 @@ private PartialIndexFilter evaluatePartialFilter(String filterExpression, Persis
510554 return PartialIndexFilter .of (BsonUtils .parse (filterExpression , null ));
511555 }
512556
557+ private org .bson .Document evaluateWildcardProjection (String projectionExpression , PersistentEntity <?, ?> entity ) {
558+
559+ Object result = evaluate (projectionExpression , getEvaluationContextForProperty (entity ));
560+
561+ if (result instanceof org .bson .Document ) {
562+ return (org .bson .Document ) result ;
563+ }
564+
565+ return BsonUtils .parse (projectionExpression , null );
566+ }
567+
568+ private Collation evaluateCollation (String collationExpression , PersistentEntity <?, ?> entity ) {
569+
570+ Object result = evaluate (collationExpression , getEvaluationContextForProperty (entity ));
571+ if (result instanceof org .bson .Document ) {
572+ return Collation .from ((org .bson .Document ) result );
573+ }
574+ if (result instanceof Collation ) {
575+ return (Collation ) result ;
576+ }
577+ if (result instanceof String ) {
578+ return Collation .parse (result .toString ());
579+ }
580+ throw new IllegalStateException ("Cannot parse collation " + result );
581+
582+ }
583+
513584 /**
514585 * Creates {@link HashedIndex} wrapped in {@link IndexDefinitionHolder} out of {@link HashIndexed} for a given
515586 * {@link MongoPersistentProperty}.
@@ -657,8 +728,8 @@ private void resolveAndAddIndexesForAssociation(Association<MongoPersistentPrope
657728 propertyDotPath ));
658729 }
659730
660- List <IndexDefinitionHolder > indexDefinitions = createIndexDefinitionHolderForProperty (propertyDotPath .toString (), collection ,
661- property );
731+ List <IndexDefinitionHolder > indexDefinitions = createIndexDefinitionHolderForProperty (propertyDotPath .toString (),
732+ collection , property );
662733
663734 if (!indexDefinitions .isEmpty ()) {
664735 indexes .addAll (indexDefinitions );
@@ -998,6 +1069,11 @@ public org.bson.Document getIndexKeys() {
9981069 public org .bson .Document getIndexOptions () {
9991070 return indexDefinition .getIndexOptions ();
10001071 }
1072+
1073+ @ Override
1074+ public String toString () {
1075+ return "IndexDefinitionHolder{" + "indexKeys=" + getIndexKeys () + '}' ;
1076+ }
10011077 }
10021078
10031079 /**
0 commit comments