From 1e32e3b0e7d959ed7a2d18f44994efbe76c4b44f Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Mon, 10 Jun 2024 16:24:02 +0200 Subject: [PATCH] Fix id conversion for fields of complex id. This commit fixes an issue where the property type for nested fields of an complex id is not handed over correctly leading to wrong conversion results eg. for Instant types that got then turned into ObjectIds. Closes #4707 Original pull request: #4719 --- .../mongodb/core/convert/QueryMapper.java | 7 +++- .../data/mongodb/core/MongoTemplateTests.java | 34 +++++++++++++++++-- .../mongodb/test/util/MongoTestTemplate.java | 9 ++++- 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java index d8135849b8..7fa4da3404 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java @@ -728,7 +728,12 @@ private Object convertIdField(Field documentField, Object source) { } else if (isKeyword(key)) { resultDbo.put(key, convertIdField(documentField, entry.getValue())); } else { - resultDbo.put(key, getMappedValue(documentField, entry.getValue())); + if(documentField.getProperty() != null && documentField.getProperty().isEntity()) { + Field propertyField = createPropertyField(documentField.getPropertyEntity(), key, mappingContext); + resultDbo.put(key, getMappedValue(propertyField, entry.getValue())); + } else { + resultDbo.put(key, getMappedValue(documentField, entry.getValue())); + } } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java index a1543aba86..c1126165da 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java @@ -1409,18 +1409,21 @@ public void executesQueryWithNegatedRegexCorrectly() { assertThat(result.get(0).field).isEqualTo("Beauford"); } - @Test // DATAMONGO-447 + @Test // DATAMONGO-447, GH-4707 public void storesAndRemovesTypeWithComplexId() { MyId id = new MyId(); + id.id = Instant.now().minusSeconds(2); id.first = "foo"; id.second = "bar"; + id.time = Instant.now().minusSeconds(3); TypeWithMyId source = new TypeWithMyId(); source.id = id; template.save(source); - template.remove(query(where("id").is(id)), TypeWithMyId.class); + assertThat(template.remove(query(where("id").is(id)), TypeWithMyId.class)).extracting(DeleteResult::getDeletedCount) + .isEqualTo(1L); } @Test // DATAMONGO-506 @@ -2554,6 +2557,29 @@ public void findAndReplaceShouldProjectReturnedObjectCorrectly() { assertThat(projection.getName()).isEqualTo("Walter"); } + @Test // GH-4707 + public void findAndReplaceUpsertsObjectWithComplexId() { + + MyId id = new MyId(); + id.id = Instant.now().minusSeconds(2); + id.first = "foo"; + id.second = "bar"; + id.time = Instant.now().minusSeconds(3); + + TypeWithMyId replacement = new TypeWithMyId(); + replacement.value = "spring"; + + template.findAndReplace(query(where("id").is(id)), replacement, FindAndReplaceOptions.options().upsert()); + template.doInCollection(TypeWithMyId.class, collection -> { + + org.bson.Document dbValue = collection.find(new org.bson.Document("_id.first", "foo")).first(); + + assertThat(dbValue).isNotNull(); + assertThat(dbValue.getEmbedded(List.of("_id", "_id"), Object.class)).isInstanceOf(Date.class); + assertThat(dbValue.getEmbedded(List.of("_id", "t"), Object.class)).isInstanceOf(Date.class); + }); + } + @Test // GH-4609 public void shouldReadNestedProjection() { @@ -4397,11 +4423,15 @@ static class MyId { String first; String second; + Instant time; + + @Field("t") Instant time; } static class TypeWithMyId { @Id MyId id; + String value; } static class Sample { diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/test/util/MongoTestTemplate.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/test/util/MongoTestTemplate.java index bab535cb56..1b4c3a1e27 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/test/util/MongoTestTemplate.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/test/util/MongoTestTemplate.java @@ -25,11 +25,11 @@ import org.springframework.data.mapping.callback.EntityCallbacks; import org.springframework.data.mapping.context.PersistentEntities; import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.util.MongoCompatibilityAdapter; import com.mongodb.MongoWriteException; import com.mongodb.client.MongoClient; import com.mongodb.client.MongoCollection; -import org.springframework.data.mongodb.util.MongoCompatibilityAdapter; /** * A {@link MongoTemplate} with configuration hooks and extension suitable for tests. @@ -147,4 +147,11 @@ public void dropIndexes(Class... entities) { getCollection(getCollectionName(entity)).dropIndexes(); } } + + public void doInCollection(Class entityClass, Consumer> callback) { + execute(entityClass, (collection -> { + callback.accept(collection); + return null; + })); + } }