Skip to content

Commit 5178eeb

Browse files
christophstroblmp911de
authored andcommitted
DATAMONGO-2388 - Fix CodecConfigurationException when reading index info that contains DbRef.
Provide the default CodecRegistry when converting partial index data to its String representation used in IndexInfo. Original pull request: #797.
1 parent bc5e7fa commit 5178eeb

File tree

3 files changed

+114
-3
lines changed

3 files changed

+114
-3
lines changed

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

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import java.util.Optional;
2727

2828
import org.bson.Document;
29+
import org.springframework.data.mongodb.util.BsonUtils;
2930
import org.springframework.lang.Nullable;
3031
import org.springframework.util.Assert;
3132
import org.springframework.util.NumberUtils;
@@ -117,9 +118,8 @@ public static IndexInfo indexInfoOf(Document sourceDocument) {
117118
boolean sparse = sourceDocument.containsKey("sparse") ? (Boolean) sourceDocument.get("sparse") : false;
118119
String language = sourceDocument.containsKey("default_language") ? (String) sourceDocument.get("default_language")
119120
: "";
120-
String partialFilter = sourceDocument.containsKey("partialFilterExpression")
121-
? ((Document) sourceDocument.get("partialFilterExpression")).toJson()
122-
: null;
121+
122+
String partialFilter = extractPartialFilterString(sourceDocument);
123123

124124
IndexInfo info = new IndexInfo(indexFields, name, unique, sparse, language);
125125
info.partialFilterExpression = partialFilter;
@@ -134,6 +134,21 @@ public static IndexInfo indexInfoOf(Document sourceDocument) {
134134
return info;
135135
}
136136

137+
/**
138+
* @param sourceDocument
139+
* @return the {@link String} representation of the partial filter {@link Document}.
140+
* @since 2.1.11
141+
*/
142+
@Nullable
143+
private static String extractPartialFilterString(Document sourceDocument) {
144+
145+
if (!sourceDocument.containsKey("partialFilterExpression")) {
146+
return null;
147+
}
148+
149+
return BsonUtils.toJson(sourceDocument.get("partialFilterExpression", Document.class));
150+
}
151+
137152
/**
138153
* Returns the individual index fields of the index.
139154
*

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/BsonUtils.java

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,26 @@
1616
package org.springframework.data.mongodb.util;
1717

1818
import java.util.Arrays;
19+
import java.util.Collection;
1920
import java.util.Date;
2021
import java.util.Map;
2122
import java.util.function.Function;
23+
import java.util.stream.Collectors;
24+
import java.util.stream.StreamSupport;
2225

2326
import org.bson.BsonValue;
2427
import org.bson.Document;
2528
import org.bson.conversions.Bson;
29+
import org.bson.json.JsonParseException;
30+
import org.springframework.core.convert.converter.Converter;
2631
import org.springframework.lang.Nullable;
2732
import org.springframework.util.ObjectUtils;
2833
import org.springframework.util.StringUtils;
2934

3035
import com.mongodb.BasicDBObject;
3136
import com.mongodb.DBObject;
3237
import com.mongodb.DBRef;
38+
import com.mongodb.MongoClientSettings;
3339

3440
/**
3541
* @author Christoph Strobl
@@ -147,4 +153,77 @@ public static Document toDocumentOrElse(String source, Function<String, Document
147153
return orElse.apply(source);
148154
}
149155

156+
/**
157+
* Serialize the given {@link Document} as Json applying default codecs if necessary.
158+
*
159+
* @param source
160+
* @return
161+
* @since 2.1.1
162+
*/
163+
public static String toJson(Document source) {
164+
165+
if (source == null) {
166+
return null;
167+
}
168+
169+
try {
170+
return source.toJson();
171+
} catch (Exception e) {
172+
return toJson((Object) source);
173+
}
174+
}
175+
176+
private static String toJson(Object value) {
177+
178+
if (value == null) {
179+
return null;
180+
}
181+
182+
try {
183+
return value instanceof Document
184+
? ((Document) value).toJson(MongoClientSettings.getDefaultCodecRegistry().get(Document.class))
185+
: serializeValue(value);
186+
187+
} catch (Exception e) {
188+
189+
if (value instanceof Collection) {
190+
return toString((Collection<?>) value);
191+
} else if (value instanceof Map) {
192+
return toString((Map<?, ?>) value);
193+
} else if (ObjectUtils.isArray(value)) {
194+
return toString(Arrays.asList(ObjectUtils.toObjectArray(value)));
195+
}
196+
197+
throw e instanceof JsonParseException ? (JsonParseException) e : new JsonParseException(e);
198+
}
199+
}
200+
201+
private static String serializeValue(@Nullable Object value) {
202+
203+
if (value == null) {
204+
return "null";
205+
}
206+
207+
String documentJson = new Document("toBeEncoded", value).toJson();
208+
return documentJson.substring(documentJson.indexOf(':') + 1, documentJson.length() - 1).trim();
209+
}
210+
211+
private static String toString(Map<?, ?> source) {
212+
213+
return iterableToDelimitedString(source.entrySet(), "{ ", " }",
214+
entry -> String.format("\"%s\" : %s", entry.getKey(), toJson(entry.getValue())));
215+
}
216+
217+
private static String toString(Collection<?> source) {
218+
return iterableToDelimitedString(source, "[ ", " ]", BsonUtils::toJson);
219+
}
220+
221+
private static <T> String iterableToDelimitedString(Iterable<T> source, String prefix, String postfix,
222+
Converter<? super T, Object> transformer) {
223+
224+
return prefix
225+
+ StringUtils.collectionToCommaDelimitedString(
226+
StreamSupport.stream(source.spliterator(), false).map(transformer::convert).collect(Collectors.toList()))
227+
+ postfix;
228+
}
150229
}

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import static org.springframework.data.mongodb.core.index.PartialIndexFilter.*;
2121
import static org.springframework.data.mongodb.core.query.Criteria.*;
2222

23+
import org.bson.BsonDocument;
2324
import org.bson.Document;
2425
import org.junit.Before;
2526
import org.junit.Test;
@@ -39,6 +40,7 @@
3940
import org.springframework.util.ObjectUtils;
4041

4142
import com.mongodb.client.MongoCollection;
43+
import com.mongodb.client.model.IndexOptions;
4244

4345
/**
4446
* Integration tests for {@link DefaultIndexOperations}.
@@ -153,6 +155,21 @@ public void shouldFavorExplicitMappingHintViaClass() {
153155
.isEqualTo(Document.parse("{ \"a_g_e\" : { \"$gte\" : 10 } }"));
154156
}
155157

158+
@Test // DATAMONGO-2388
159+
public void shouldReadIndexWithPartialFilterContainingDbRefCorrectly() {
160+
161+
BsonDocument partialFilter = BsonDocument.parse(
162+
"{ \"the-ref\" : { \"$ref\" : \"other-collection\", \"$id\" : { \"$oid\" : \"59ce08baf264b906810fe8c5\"} } }");
163+
IndexOptions indexOptions = new IndexOptions();
164+
indexOptions.name("partial-with-dbref");
165+
indexOptions.partialFilterExpression(partialFilter);
166+
167+
collection.createIndex(BsonDocument.parse("{ \"key-1\" : 1, \"key-2\": 1}"), indexOptions);
168+
169+
IndexInfo info = findAndReturnIndexInfo(indexOps.getIndexInfo(), "partial-with-dbref");
170+
assertThat(BsonDocument.parse(info.getPartialFilterExpression())).isEqualTo(partialFilter);
171+
}
172+
156173
@Test // DATAMONGO-1518
157174
public void shouldCreateIndexWithCollationCorrectly() {
158175

0 commit comments

Comments
 (0)