15
15
*/
16
16
package org .springframework .data .mongodb .core .index ;
17
17
18
+ import java .lang .annotation .Annotation ;
18
19
import java .time .Duration ;
19
20
import java .util .ArrayList ;
20
21
import java .util .Arrays ;
23
24
import java .util .HashSet ;
24
25
import java .util .Iterator ;
25
26
import java .util .List ;
27
+ import java .util .Map ;
26
28
import java .util .Set ;
27
29
import java .util .concurrent .TimeUnit ;
30
+ import java .util .function .Supplier ;
28
31
import java .util .stream .Collectors ;
29
32
30
33
import org .apache .commons .logging .Log ;
31
34
import org .apache .commons .logging .LogFactory ;
32
-
35
+ import org . springframework . core . annotation . MergedAnnotation ;
33
36
import org .springframework .dao .InvalidDataAccessApiUsageException ;
34
37
import org .springframework .data .domain .Sort ;
35
38
import org .springframework .data .mapping .Association ;
50
53
import org .springframework .data .mongodb .core .query .Collation ;
51
54
import org .springframework .data .mongodb .util .BsonUtils ;
52
55
import org .springframework .data .mongodb .util .DotPath ;
56
+ import org .springframework .data .mongodb .util .spel .ExpressionUtils ;
53
57
import org .springframework .data .spel .EvaluationContextProvider ;
54
58
import org .springframework .data .util .TypeInformation ;
55
59
import org .springframework .expression .EvaluationContext ;
56
- import org .springframework .expression .Expression ;
57
- import org .springframework .expression .ParserContext ;
58
- import org .springframework .expression .common .LiteralExpression ;
59
60
import org .springframework .expression .spel .standard .SpelExpressionParser ;
60
61
import org .springframework .lang .Nullable ;
61
62
import org .springframework .util .Assert ;
@@ -454,10 +455,7 @@ protected IndexDefinitionHolder createCompoundIndexDefinition(String dotPath, St
454
455
indexDefinition .partial (evaluatePartialFilter (index .partialFilter (), entity ));
455
456
}
456
457
457
- if (StringUtils .hasText (index .collation ())) {
458
- indexDefinition .collation (evaluateCollation (index .collation (), entity ));
459
- }
460
-
458
+ indexDefinition .collation (resolveCollation (index , entity ));
461
459
return new IndexDefinitionHolder (dotPath , indexDefinition , collection );
462
460
}
463
461
@@ -478,12 +476,7 @@ protected IndexDefinitionHolder createWildcardIndexDefinition(String dotPath, St
478
476
indexDefinition .partial (evaluatePartialFilter (index .partialFilter (), entity ));
479
477
}
480
478
481
- if (StringUtils .hasText (index .collation ())) {
482
- indexDefinition .collation (evaluateCollation (index .collation (), entity ));
483
- } else if (entity != null && entity .hasCollation ()) {
484
- indexDefinition .collation (entity .getCollation ());
485
- }
486
-
479
+ indexDefinition .collation (resolveCollation (index , entity ));
487
480
return new IndexDefinitionHolder (dotPath , indexDefinition , collection );
488
481
}
489
482
@@ -498,7 +491,7 @@ private org.bson.Document resolveCompoundIndexKeyFromStringDefinition(String dot
498
491
return new org .bson .Document (dotPath , 1 );
499
492
}
500
493
501
- Object keyDefToUse = evaluate (keyDefinitionString , getEvaluationContextForProperty (entity ));
494
+ Object keyDefToUse = ExpressionUtils . evaluate (keyDefinitionString , () -> getEvaluationContextForProperty (entity ));
502
495
503
496
org .bson .Document dbo = (keyDefToUse instanceof org .bson .Document ) ? (org .bson .Document ) keyDefToUse
504
497
: org .bson .Document .parse (ObjectUtils .nullSafeToString (keyDefToUse ));
@@ -567,7 +560,7 @@ protected IndexDefinitionHolder createIndexDefinition(String dotPath, String col
567
560
}
568
561
569
562
Duration timeout = computeIndexTimeout (index .expireAfter (),
570
- getEvaluationContextForProperty (persistentProperty .getOwner ()));
563
+ () -> getEvaluationContextForProperty (persistentProperty .getOwner ()));
571
564
if (!timeout .isZero () && !timeout .isNegative ()) {
572
565
indexDefinition .expire (timeout );
573
566
}
@@ -577,16 +570,13 @@ protected IndexDefinitionHolder createIndexDefinition(String dotPath, String col
577
570
indexDefinition .partial (evaluatePartialFilter (index .partialFilter (), persistentProperty .getOwner ()));
578
571
}
579
572
580
- if (StringUtils .hasText (index .collation ())) {
581
- indexDefinition .collation (evaluateCollation (index .collation (), persistentProperty .getOwner ()));
582
- }
583
-
573
+ indexDefinition .collation (resolveCollation (index , persistentProperty .getOwner ()));
584
574
return new IndexDefinitionHolder (dotPath , indexDefinition , collection );
585
575
}
586
576
587
577
private PartialIndexFilter evaluatePartialFilter (String filterExpression , PersistentEntity <?, ?> entity ) {
588
578
589
- Object result = evaluate (filterExpression , getEvaluationContextForProperty (entity ));
579
+ Object result = ExpressionUtils . evaluate (filterExpression , () -> getEvaluationContextForProperty (entity ));
590
580
591
581
if (result instanceof org .bson .Document ) {
592
582
return PartialIndexFilter .of ((org .bson .Document ) result );
@@ -597,7 +587,7 @@ private PartialIndexFilter evaluatePartialFilter(String filterExpression, Persis
597
587
598
588
private org .bson .Document evaluateWildcardProjection (String projectionExpression , PersistentEntity <?, ?> entity ) {
599
589
600
- Object result = evaluate (projectionExpression , getEvaluationContextForProperty (entity ));
590
+ Object result = ExpressionUtils . evaluate (projectionExpression , () -> getEvaluationContextForProperty (entity ));
601
591
602
592
if (result instanceof org .bson .Document ) {
603
593
return (org .bson .Document ) result ;
@@ -608,7 +598,7 @@ private org.bson.Document evaluateWildcardProjection(String projectionExpression
608
598
609
599
private Collation evaluateCollation (String collationExpression , PersistentEntity <?, ?> entity ) {
610
600
611
- Object result = evaluate (collationExpression , getEvaluationContextForProperty (entity ));
601
+ Object result = ExpressionUtils . evaluate (collationExpression , () -> getEvaluationContextForProperty (entity ));
612
602
if (result instanceof org .bson .Document ) {
613
603
return Collation .from ((org .bson .Document ) result );
614
604
}
@@ -618,6 +608,9 @@ private Collation evaluateCollation(String collationExpression, PersistentEntity
618
608
if (result instanceof String ) {
619
609
return Collation .parse (result .toString ());
620
610
}
611
+ if (result instanceof Map ) {
612
+ return Collation .from (new org .bson .Document ((Map <String , ?>) result ));
613
+ }
621
614
throw new IllegalStateException ("Cannot parse collation " + result );
622
615
623
616
}
@@ -726,7 +719,7 @@ private String pathAwareIndexName(String indexName, String dotPath, @Nullable Pe
726
719
String nameToUse = "" ;
727
720
if (StringUtils .hasText (indexName )) {
728
721
729
- Object result = evaluate (indexName , getEvaluationContextForProperty (entity ));
722
+ Object result = ExpressionUtils . evaluate (indexName , () -> getEvaluationContextForProperty (entity ));
730
723
731
724
if (result != null ) {
732
725
nameToUse = ObjectUtils .nullSafeToString (result );
@@ -787,9 +780,9 @@ private void resolveAndAddIndexesForAssociation(Association<MongoPersistentPrope
787
780
* @since 2.2
788
781
* @throws IllegalArgumentException for invalid duration values.
789
782
*/
790
- private static Duration computeIndexTimeout (String timeoutValue , EvaluationContext evaluationContext ) {
783
+ private static Duration computeIndexTimeout (String timeoutValue , Supplier < EvaluationContext > evaluationContext ) {
791
784
792
- Object evaluatedTimeout = evaluate (timeoutValue , evaluationContext );
785
+ Object evaluatedTimeout = ExpressionUtils . evaluate (timeoutValue , evaluationContext );
793
786
794
787
if (evaluatedTimeout == null ) {
795
788
return Duration .ZERO ;
@@ -808,15 +801,25 @@ private static Duration computeIndexTimeout(String timeoutValue, EvaluationConte
808
801
return DurationStyle .detectAndParse (val );
809
802
}
810
803
804
+ /**
805
+ * Resolve the "collation" attribute from a given {@link Annotation} if present.
806
+ *
807
+ * @param annotation
808
+ * @param entity
809
+ * @return the collation present on either the annotation or the entity as a fallback. Might be {@literal null}.
810
+ * @since 4.0
811
+ */
811
812
@ Nullable
812
- private static Object evaluate (String value , EvaluationContext evaluationContext ) {
813
+ private Collation resolveCollation (Annotation annotation , @ Nullable PersistentEntity <?, ?> entity ) {
814
+ return MergedAnnotation .from (annotation ).getValue ("collation" , String .class ).filter (StringUtils ::hasText )
815
+ .map (it -> evaluateCollation (it , entity )).orElseGet (() -> {
813
816
814
- Expression expression = PARSER . parseExpression ( value , ParserContext . TEMPLATE_EXPRESSION );
815
- if ( expression instanceof LiteralExpression ) {
816
- return value ;
817
- }
818
-
819
- return expression . getValue ( evaluationContext , Object . class );
817
+ if ( entity instanceof MongoPersistentEntity <?> mongoPersistentEntity
818
+ && mongoPersistentEntity . hasCollation () ) {
819
+ return mongoPersistentEntity . getCollation () ;
820
+ }
821
+ return null ;
822
+ } );
820
823
}
821
824
822
825
private static boolean isMapWithoutWildcardIndex (MongoPersistentProperty property ) {
0 commit comments