Skip to content

Commit 3c16b4d

Browse files
christophstroblmp911de
authored andcommitted
DATAMONGO-1509 - Write type hint as last element of a Document.
Always add type hint as last property of a Document. This is necessary to assure document equality within MongoDB in cases where the query contains full document comparisons. Unfortunately this also might break existing stuff since the order of properties within a Document is changed with this commit. Original pull request: spring-projects#411.
1 parent 070d784 commit 3c16b4d

File tree

4 files changed

+58
-14
lines changed

4 files changed

+58
-14
lines changed

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java

+7-7
Original file line numberDiff line numberDiff line change
@@ -359,20 +359,20 @@ public void write(final Object obj, final Bson bson) {
359359
return;
360360
}
361361

362-
Class<?> entityType = obj.getClass();
363-
boolean handledByCustomConverter = conversions.getCustomWriteTarget(entityType, Document.class) != null;
362+
Class<?> entityType = ClassUtils.getUserClass(obj.getClass());
364363
TypeInformation<? extends Object> type = ClassTypeInformation.from(entityType);
365364

366-
if (!handledByCustomConverter && !(bson instanceof Collection)) {
367-
typeMapper.writeType(type, bson);
368-
}
369-
370365
Object target = obj instanceof LazyLoadingProxy ? ((LazyLoadingProxy) obj).getTarget() : obj;
371366

372367
writeInternal(target, bson, type);
373368
if (asMap(bson).containsKey("_is") && asMap(bson).get("_id") == null) {
374369
removeFromMap(bson, "_id");
375370
}
371+
372+
boolean handledByCustomConverter = conversions.getCustomWriteTarget(entityType, Document.class) != null;
373+
if (!handledByCustomConverter && !(bson instanceof Collection)) {
374+
typeMapper.writeType(type, bson);
375+
}
376376
}
377377

378378
/**
@@ -529,12 +529,12 @@ protected void writePropertyInternal(Object obj, Bson bson, MongoPersistentPrope
529529

530530
Object existingValue = accessor.get(prop);
531531
Document document = existingValue instanceof Document ? (Document) existingValue : new Document();
532-
addCustomTypeKeyIfNecessary(ClassTypeInformation.from(prop.getRawType()), obj, document);
533532

534533
MongoPersistentEntity<?> entity = isSubtype(prop.getType(), obj.getClass())
535534
? mappingContext.getPersistentEntity(obj.getClass()) : mappingContext.getPersistentEntity(type);
536535

537536
writeInternal(obj, document, entity);
537+
addCustomTypeKeyIfNecessary(ClassTypeInformation.from(prop.getRawType()), obj, document);
538538
accessor.put(prop, document);
539539
}
540540

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

+20
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import static org.hamcrest.Matchers.*;
1919
import static org.junit.Assert.*;
2020

21+
import java.util.Iterator;
2122
import java.util.List;
2223

2324
import org.bson.Document;
@@ -80,4 +81,23 @@ public static <T> T getTypedValue(Document source, String key, Class<T> type) {
8081

8182
return (T) value;
8283
}
84+
85+
public static void assertTypeHint(Document document, Class<?> type) {
86+
assertTypeHint(document, type.getName());
87+
}
88+
89+
public static void assertTypeHint(Document document, String expectedTypeString) {
90+
91+
Iterator<String> keyIterator = document.keySet().iterator();
92+
while (keyIterator.hasNext()) {
93+
String key = keyIterator.next();
94+
if (key.equals("_class")) {
95+
assertThat((String) document.get(key), is(equalTo(expectedTypeString)));
96+
assertThat(keyIterator.hasNext(), is(false));
97+
return;
98+
}
99+
}
100+
101+
fail(String.format("Expected to find type info %s in %s.", document, expectedTypeString));
102+
}
83103
}

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

+19
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import org.joda.time.DateTime;
4545
import org.junit.After;
4646
import org.junit.Before;
47+
import org.junit.Ignore;
4748
import org.junit.Rule;
4849
import org.junit.Test;
4950
import org.junit.rules.ExpectedException;
@@ -3486,6 +3487,22 @@ public void onBeforeSave(BeforeSaveEvent<Document> event) {
34863487
assertThat(document.id, is(notNullValue()));
34873488
}
34883489

3490+
3491+
/**
3492+
* @see DATAMONGO-1509
3493+
*/
3494+
@Test
3495+
public void findsByGnericNestedListElements() {
3496+
3497+
List<Model> modelList = Arrays.<Model>asList(new ModelA("value"));
3498+
DocumentWithCollection dwc = new DocumentWithCollection(modelList);
3499+
3500+
template.insert(dwc);
3501+
3502+
Query query = query(where("models").is(modelList));
3503+
assertThat(template.findOne(query, DocumentWithCollection.class), is(equalTo(dwc)));
3504+
}
3505+
34893506
static class TypeWithNumbers {
34903507

34913508
@Id String id;
@@ -3565,6 +3582,7 @@ static class DocumentWithDBRefCollection {
35653582
@org.springframework.data.mongodb.core.mapping.DBRef(lazy = true) public Map<String, Sample> lazyDbRefAnnotatedMap;
35663583
}
35673584

3585+
@EqualsAndHashCode
35683586
static class DocumentWithCollection {
35693587

35703588
@Id String id;
@@ -3617,6 +3635,7 @@ static interface Model {
36173635
String id();
36183636
}
36193637

3638+
@EqualsAndHashCode
36203639
static class ModelA implements Model {
36213640

36223641
@Id String id;

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

+12-7
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,9 @@ public void maybeConvertHandlesNullValuesCorrectly() {
526526
assertThat(converter.convertToMongoType(null), is(nullValue()));
527527
}
528528

529+
/**
530+
* @see DATAMONGO-1509
531+
*/
529532
@Test
530533
public void writesGenericTypeCorrectly() {
531534

@@ -537,7 +540,7 @@ public void writesGenericTypeCorrectly() {
537540
converter.write(type, result);
538541

539542
org.bson.Document content = (org.bson.Document) result.get("content");
540-
assertThat(content.get("_class"), is(notNullValue()));
543+
assertTypeHint(content, Address.class);
541544
assertThat(content.get("city"), is(notNullValue()));
542545
}
543546

@@ -1272,6 +1275,7 @@ public void eagerlyReturnsDBRefObjectIfTargetAlreadyIsOne() {
12721275

12731276
/**
12741277
* @see DATAMONGO-523
1278+
* @see DATAMONGO-1509
12751279
*/
12761280
@Test
12771281
public void considersTypeAliasAnnotation() {
@@ -1282,9 +1286,7 @@ public void considersTypeAliasAnnotation() {
12821286
org.bson.Document result = new org.bson.Document();
12831287
converter.write(aliased, result);
12841288

1285-
Object type = result.get("_class");
1286-
assertThat(type, is(notNullValue()));
1287-
assertThat(type.toString(), is("_"));
1289+
assertTypeHint(result, "_");
12881290
}
12891291

12901292
/**
@@ -1409,6 +1411,7 @@ public void writesProjectingTypeCorrectly() {
14091411
/**
14101412
* @see DATAMONGO-812
14111413
* @see DATAMONGO-893
1414+
* @see DATAMONGO-1509
14121415
*/
14131416
@Test
14141417
public void convertsListToBasicDBListAndRetainsTypeInformationForComplexObjects() {
@@ -1424,7 +1427,7 @@ public void convertsListToBasicDBListAndRetainsTypeInformationForComplexObjects(
14241427

14251428
List<Object> dbList = (List<Object>) result;
14261429
assertThat(dbList, hasSize(1));
1427-
assertThat(getTypedValue(getAsDocument(dbList, 0), "_class", String.class), equalTo(Address.class.getName()));
1430+
assertTypeHint(getAsDocument(dbList, 0), Address.class);
14281431
}
14291432

14301433
/**
@@ -1444,6 +1447,7 @@ public void convertsListToBasicDBListWithoutTypeInformationForSimpleTypes() {
14441447

14451448
/**
14461449
* @see DATAMONGO-812
1450+
* @see DATAMONGO-1509
14471451
*/
14481452
@Test
14491453
public void convertsArrayToBasicDBListAndRetainsTypeInformationForComplexObjects() {
@@ -1458,7 +1462,7 @@ public void convertsArrayToBasicDBListAndRetainsTypeInformationForComplexObjects
14581462

14591463
List<Object> dbList = (List<Object>) result;
14601464
assertThat(dbList, hasSize(1));
1461-
assertThat(getTypedValue(getAsDocument(dbList, 0), "_class", String.class), equalTo(Address.class.getName()));
1465+
assertTypeHint(getAsDocument(dbList, 0), Address.class);
14621466
}
14631467

14641468
/**
@@ -1802,6 +1806,7 @@ public void shouldIncludeTextScorePropertyWhenReading() {
18021806

18031807
/**
18041808
* @see DATAMONGO-1001
1809+
* @see DATAMONGO-1509
18051810
*/
18061811
@Test
18071812
public void shouldWriteCglibProxiedClassTypeInformationCorrectly() {
@@ -1814,7 +1819,7 @@ public void shouldWriteCglibProxiedClassTypeInformationCorrectly() {
18141819
org.bson.Document document = new org.bson.Document();
18151820
converter.write(proxied, document);
18161821

1817-
assertThat(document.get("_class"), is((Object) GenericType.class.getName()));
1822+
assertTypeHint(document, GenericType.class);
18181823
}
18191824

18201825
/**

0 commit comments

Comments
 (0)