Skip to content

Commit 5c80ee0

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 adb9dc2 commit 5c80ee0

File tree

3 files changed

+120
-2
lines changed

3 files changed

+120
-2
lines changed

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

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

2727
import org.bson.Document;
28+
import org.springframework.data.mongodb.util.BsonUtils;
2829
import org.springframework.lang.Nullable;
2930
import org.springframework.util.Assert;
3031
import org.springframework.util.ObjectUtils;
@@ -107,15 +108,30 @@ public static IndexInfo indexInfoOf(Document sourceDocument) {
107108
boolean sparse = sourceDocument.containsKey("sparse") ? (Boolean) sourceDocument.get("sparse") : false;
108109
String language = sourceDocument.containsKey("default_language") ? (String) sourceDocument.get("default_language")
109110
: "";
110-
String partialFilter = sourceDocument.containsKey("partialFilterExpression")
111-
? ((Document) sourceDocument.get("partialFilterExpression")).toJson() : null;
111+
112+
String partialFilter = extractPartialFilterString(sourceDocument);
112113

113114
IndexInfo info = new IndexInfo(indexFields, name, unique, sparse, language);
114115
info.partialFilterExpression = partialFilter;
115116
info.collation = sourceDocument.get("collation", Document.class);
116117
return info;
117118
}
118119

120+
/**
121+
* @param sourceDocument
122+
* @return the {@link String} representation of the partial filter {@link Document}.
123+
* @since 2.1.11
124+
*/
125+
@Nullable
126+
private static String extractPartialFilterString(Document sourceDocument) {
127+
128+
if (!sourceDocument.containsKey("partialFilterExpression")) {
129+
return null;
130+
}
131+
132+
return BsonUtils.toJson(sourceDocument.get("partialFilterExpression", Document.class));
133+
}
134+
119135
/**
120136
* Returns the individual index fields of the index.
121137
*

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

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,27 @@
1515
*/
1616
package org.springframework.data.mongodb.util;
1717

18+
import java.util.Arrays;
19+
import java.util.Collection;
1820
import java.util.Date;
1921
import java.util.Map;
22+
import java.util.stream.Collectors;
23+
import java.util.stream.StreamSupport;
2024

2125
import org.bson.BsonValue;
2226
import org.bson.Document;
2327
import org.bson.conversions.Bson;
28+
import org.bson.json.JsonParseException;
29+
30+
import org.springframework.core.convert.converter.Converter;
2431
import org.springframework.lang.Nullable;
32+
import org.springframework.util.ObjectUtils;
33+
import org.springframework.util.StringUtils;
2534

2635
import com.mongodb.BasicDBObject;
2736
import com.mongodb.DBObject;
2837
import com.mongodb.DBRef;
38+
import com.mongodb.MongoClientSettings;
2939

3040
/**
3141
* @author Christoph Strobl
@@ -104,4 +114,79 @@ public static Object toJavaType(BsonValue value) {
104114
return value;
105115
}
106116
}
117+
118+
/**
119+
* Serialize the given {@link Document} as Json applying default codecs if necessary.
120+
*
121+
* @param source
122+
* @return
123+
* @since 2.1.1
124+
*/
125+
@Nullable
126+
public static String toJson(@Nullable Document source) {
127+
128+
if (source == null) {
129+
return null;
130+
}
131+
132+
try {
133+
return source.toJson();
134+
} catch (Exception e) {
135+
return toJson((Object) source);
136+
}
137+
}
138+
139+
private static String toJson(@Nullable Object value) {
140+
141+
if (value == null) {
142+
return null;
143+
}
144+
145+
try {
146+
return value instanceof Document
147+
? ((Document) value).toJson(MongoClientSettings.getDefaultCodecRegistry().get(Document.class))
148+
: serializeValue(value);
149+
150+
} catch (Exception e) {
151+
152+
if (value instanceof Collection) {
153+
return toString((Collection<?>) value);
154+
} else if (value instanceof Map) {
155+
return toString((Map<?, ?>) value);
156+
} else if (ObjectUtils.isArray(value)) {
157+
return toString(Arrays.asList(ObjectUtils.toObjectArray(value)));
158+
}
159+
160+
throw e instanceof JsonParseException ? (JsonParseException) e : new JsonParseException(e);
161+
}
162+
}
163+
164+
private static String serializeValue(@Nullable Object value) {
165+
166+
if (value == null) {
167+
return "null";
168+
}
169+
170+
String documentJson = new Document("toBeEncoded", value).toJson();
171+
return documentJson.substring(documentJson.indexOf(':') + 1, documentJson.length() - 1).trim();
172+
}
173+
174+
private static String toString(Map<?, ?> source) {
175+
176+
return iterableToDelimitedString(source.entrySet(), "{ ", " }",
177+
entry -> String.format("\"%s\" : %s", entry.getKey(), toJson(entry.getValue())));
178+
}
179+
180+
private static String toString(Collection<?> source) {
181+
return iterableToDelimitedString(source, "[ ", " ]", BsonUtils::toJson);
182+
}
183+
184+
private static <T> String iterableToDelimitedString(Iterable<T> source, String prefix, String postfix,
185+
Converter<? super T, Object> transformer) {
186+
187+
return prefix
188+
+ StringUtils.collectionToCommaDelimitedString(
189+
StreamSupport.stream(source.spliterator(), false).map(transformer::convert).collect(Collectors.toList()))
190+
+ postfix;
191+
}
107192
}

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
@@ -21,6 +21,7 @@
2121
import static org.springframework.data.mongodb.core.index.PartialIndexFilter.*;
2222
import static org.springframework.data.mongodb.core.query.Criteria.*;
2323

24+
import org.bson.BsonDocument;
2425
import org.bson.Document;
2526
import org.junit.Before;
2627
import org.junit.Test;
@@ -40,6 +41,7 @@
4041
import org.springframework.util.ObjectUtils;
4142

4243
import com.mongodb.client.MongoCollection;
44+
import com.mongodb.client.model.IndexOptions;
4345

4446
/**
4547
* Integration tests for {@link DefaultIndexOperations}.
@@ -150,6 +152,21 @@ public void shouldFavorExplicitMappingHintViaClass() {
150152
assertThat(info.getPartialFilterExpression()).isEqualTo("{ \"a_g_e\" : { \"$gte\" : 10 } }");
151153
}
152154

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

0 commit comments

Comments
 (0)