1616
1717package org .springframework .ai .model .chat .memory .repository .mongo .autoconfigure ;
1818
19+ import java .lang .reflect .Method ;
20+
1921import org .slf4j .Logger ;
2022import org .slf4j .LoggerFactory ;
2123
2729import org .springframework .data .domain .Sort ;
2830import org .springframework .data .mongodb .core .MongoTemplate ;
2931import org .springframework .data .mongodb .core .index .Index ;
32+ import org .springframework .data .mongodb .core .index .IndexDefinition ;
33+ import org .springframework .data .mongodb .core .index .IndexOperations ;
3034
3135/**
3236 * Class responsible for creating proper MongoDB indices for the ChatMemory. Creates a
@@ -47,35 +51,88 @@ public class MongoChatMemoryIndexCreatorAutoConfiguration {
4751
4852 private final MongoChatMemoryProperties mongoChatMemoryProperties ;
4953
50- public MongoChatMemoryIndexCreatorAutoConfiguration (MongoTemplate mongoTemplate ,
51- MongoChatMemoryProperties mongoChatMemoryProperties ) {
54+ public MongoChatMemoryIndexCreatorAutoConfiguration (final MongoTemplate mongoTemplate ,
55+ final MongoChatMemoryProperties mongoChatMemoryProperties ) {
5256 this .mongoTemplate = mongoTemplate ;
5357 this .mongoChatMemoryProperties = mongoChatMemoryProperties ;
5458 }
5559
60+ /**
61+ * Initializes MongoDB indices after application context refresh.
62+ */
5663 @ EventListener (ContextRefreshedEvent .class )
5764 public void initIndicesAfterStartup () {
5865 logger .info ("Creating MongoDB indices for ChatMemory" );
5966 // Create a main index
60- this .mongoTemplate .indexOps (Conversation .class )
61- .createIndex (new Index ().on ("conversationId" , Sort .Direction .ASC ).on ("timestamp" , Sort .Direction .DESC ));
62-
67+ createMainIndex ();
6368 createOrUpdateTtlIndex ();
6469 }
6570
71+ private void createMainIndex () {
72+ var indexOps = this .mongoTemplate .indexOps (Conversation .class );
73+ var index = new Index ().on ("conversationId" , Sort .Direction .ASC ).on ("timestamp" , Sort .Direction .DESC );
74+
75+ // Use reflection to handle API differences across Spring Data MongoDB versions
76+ createIndexSafely (indexOps , index );
77+ }
78+
6679 private void createOrUpdateTtlIndex () {
6780 if (!this .mongoChatMemoryProperties .getTtl ().isZero ()) {
81+ var indexOps = this .mongoTemplate .indexOps (Conversation .class );
6882 // Check for existing TTL index
69- this . mongoTemplate . indexOps ( Conversation . class ) .getIndexInfo ().forEach (idx -> {
83+ indexOps .getIndexInfo ().forEach (idx -> {
7084 if (idx .getExpireAfter ().isPresent ()
7185 && !idx .getExpireAfter ().get ().equals (this .mongoChatMemoryProperties .getTtl ())) {
7286 logger .warn ("Dropping existing TTL index, because TTL is different" );
73- this . mongoTemplate . indexOps ( Conversation . class ) .dropIndex (idx .getName ());
87+ indexOps .dropIndex (idx .getName ());
7488 }
7589 });
76- this .mongoTemplate .indexOps (Conversation .class )
77- .createIndex (new Index ().on ("timestamp" , Sort .Direction .ASC )
78- .expire (this .mongoChatMemoryProperties .getTtl ()));
90+ // Use reflection to handle API differences across Spring Data MongoDB
91+ // versions
92+ createIndexSafely (indexOps ,
93+ new Index ().on ("timestamp" , Sort .Direction .ASC ).expire (this .mongoChatMemoryProperties .getTtl ()));
94+ }
95+ }
96+
97+ /**
98+ * Creates an index using reflection to handle API changes across different Spring
99+ * Data MongoDB versions:
100+ * <ul>
101+ * <li>Spring Data MongoDB 4.2.x - 4.4.x: only {@code ensureIndex(IndexDefinition)} is
102+ * available.</li>
103+ * <li>Spring Data MongoDB 4.5.x+: {@code createIndex(IndexDefinition)} is the new
104+ * API, {@code ensureIndex} is deprecated.</li>
105+ * </ul>
106+ * @param indexOps the IndexOperations instance
107+ * @param index the index definition
108+ * @throws IllegalStateException if neither method is available or invocation fails
109+ */
110+ private void createIndexSafely (final IndexOperations indexOps , final IndexDefinition index ) {
111+ try {
112+ // Try new API (Spring Data MongoDB 4.5.x+)
113+ Method method = IndexOperations .class .getMethod ("createIndex" , IndexDefinition .class );
114+ method .invoke (indexOps , index );
115+ logger .debug ("Created index using createIndex() method" );
116+ }
117+ catch (NoSuchMethodException createIndexNotFound ) {
118+ // Fall back to old API (Spring Data MongoDB 4.2.x - 4.4.x)
119+ try {
120+ Method method = IndexOperations .class .getMethod ("ensureIndex" , IndexDefinition .class );
121+ method .invoke (indexOps , index );
122+ logger .debug ("Created index using ensureIndex() method" );
123+ }
124+ catch (NoSuchMethodException ensureIndexNotFound ) {
125+ throw new IllegalStateException (
126+ "Neither createIndex() nor ensureIndex() method found on IndexOperations. "
127+ + "This may indicate an unsupported Spring Data MongoDB version." ,
128+ ensureIndexNotFound );
129+ }
130+ catch (ReflectiveOperationException ex ) {
131+ throw new IllegalStateException ("Failed to invoke ensureIndex() method" , ex );
132+ }
133+ }
134+ catch (ReflectiveOperationException ex ) {
135+ throw new IllegalStateException ("Failed to invoke createIndex() method" , ex );
79136 }
80137 }
81138
0 commit comments