diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/EntityOperations.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/EntityOperations.java index bb2d2ca5a6..db07166b5a 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/EntityOperations.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/EntityOperations.java @@ -283,6 +283,10 @@ public TypedOperations forType(@Nullable Class entityClass) { * @see EntityProjectionIntrospector#introspect(Class, Class) */ public EntityProjection introspectProjection(Class resultType, Class entityType) { + + if (!queryMapper.getMappingContext().hasPersistentEntityFor(entityType)) { + return (EntityProjection) EntityProjection.nonProjecting(resultType); + } return introspector.introspect(resultType, entityType); } 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 30978bce96..c93c8ade66 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 @@ -2526,6 +2526,26 @@ public void findAndReplaceShouldProjectReturnedObjectCorrectly() { assertThat(projection.getName()).isEqualTo("Walter"); } + @Test // GH-4300 + public void findAndReplaceShouldAllowNativeDomainTypesAndReturnAProjection() { + + MyPerson person = new MyPerson("Walter"); + person.address = new Address("TX", "Austin"); + template.save(person); + + MyPerson previous = template.findAndReplace(query(where("name").is("Walter")), + new org.bson.Document("name", "Heisenberg"), FindAndReplaceOptions.options(), org.bson.Document.class, + "myPerson", MyPerson.class); + + assertThat(previous).isNotNull(); + assertThat(previous.getAddress()).isEqualTo(person.address); + + org.bson.Document loaded = template.execute(MyPerson.class, collection -> { + return collection.find(new org.bson.Document("name", "Heisenberg")).first(); + }); + assertThat(loaded.get("_id")).isEqualTo(new ObjectId(person.id)); + } + @Test // DATAMONGO-407 public void updatesShouldRetainTypeInformationEvenForCollections() { diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnitTests.java index 3f4a63232e..6ae652ef85 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnitTests.java @@ -2392,6 +2392,17 @@ void templatePassesOnTimeSeriesOptionsWhenNoTypeGiven() { .isEqualTo(new com.mongodb.client.model.TimeSeriesOptions("time_stamp").toString()); } + @Test // GH-4300 + void findAndReplaceAllowsDocumentSourceType() { + + template.findAndReplace(new Query(), new Document("spring", "data"), FindAndReplaceOptions.options().upsert(), + Document.class, "coll-1", Person.class); + + verify(db).getCollection(eq("coll-1"), eq(Document.class)); + verify(collection).findOneAndReplace((Bson) any(Bson.class), eq(new Document("spring", "data")), + any(FindOneAndReplaceOptions.class)); + } + class AutogenerateableId { @Id BigInteger id; diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateTests.java index 6ca3808c9a..7740b5a7cf 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateTests.java @@ -729,6 +729,32 @@ void findAndReplaceShouldProjectReturnedObjectCorrectly() { }).verifyComplete(); } + @Test // GH-4300 + public void findAndReplaceShouldAllowNativeDomainTypesAndReturnAProjection() { + + MongoTemplateTests.MyPerson person = new MongoTemplateTests.MyPerson("Walter"); + person.address = new Address("TX", "Austin"); + template.save(person) // + .as(StepVerifier::create) // + .expectNextCount(1) // + .verifyComplete(); + + template + .findAndReplace(query(where("name").is("Walter")), new org.bson.Document("name", "Heisenberg"), + FindAndReplaceOptions.options(), org.bson.Document.class, "myPerson", MongoTemplateTests.MyPerson.class) + .as(StepVerifier::create) // + .consumeNextWith(actual -> { + assertThat(actual.getAddress()).isEqualTo(person.address); + }).verifyComplete(); + + template.execute(MongoTemplateTests.MyPerson.class, collection -> { + return collection.find(new org.bson.Document("name", "Heisenberg")).first(); + }).as(StepVerifier::create) // + .consumeNextWith(loaded -> { + assertThat(loaded.get("_id")).isEqualTo(new ObjectId(person.id)); + }).verifyComplete(); + } + @Test // DATAMONGO-1827 void findAndReplaceShouldReplaceObjectReturingNew() {