Skip to content

Commit 0821f48

Browse files
JGoP-Lilayaperumalg
authored andcommitted
Fix MongoDB index creation API compatibility across Spring Data MongoDB versions
Use reflection to handle API differences between Spring Data MongoDB versions: - Spring Data MongoDB 4.2.x - 4.4.x: only ensureIndex() is available - Spring Data MongoDB 4.5.x+: createIndex() is the new API, ensureIndex is deprecated This fix ensures compatibility with both Spring Boot 3.4.x (MongoDB 4.4.x) and Spring Boot 3.5.x (MongoDB 4.5.x+), which are both officially supported versions. Fixes #4884 Signed-off-by: shaojie <[email protected]>
1 parent ef8f413 commit 0821f48

File tree

1 file changed

+67
-10
lines changed
  • auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-mongodb/src/main/java/org/springframework/ai/model/chat/memory/repository/mongo/autoconfigure

1 file changed

+67
-10
lines changed

auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-mongodb/src/main/java/org/springframework/ai/model/chat/memory/repository/mongo/autoconfigure/MongoChatMemoryIndexCreatorAutoConfiguration.java

Lines changed: 67 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package org.springframework.ai.model.chat.memory.repository.mongo.autoconfigure;
1818

19+
import java.lang.reflect.Method;
20+
1921
import org.slf4j.Logger;
2022
import org.slf4j.LoggerFactory;
2123

@@ -27,6 +29,8 @@
2729
import org.springframework.data.domain.Sort;
2830
import org.springframework.data.mongodb.core.MongoTemplate;
2931
import 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

Comments
 (0)