From 0cc050e966a28980e509e45de79e84e7cca5e944 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Thu, 19 Nov 2015 14:10:17 +0100 Subject: [PATCH] DATAMONGO-1287 - Fix double fetching for lazy DbRefs used in entity constructor. We now check properties for their usage as constructor arguments, that might already have been resolved, before setting the actual value. This prevents turning already eagerly fetched DBRefs back into LazyLoadingProxies. Original pull request: #335. Related pull request: #322. --- .../core/convert/MappingMongoConverter.java | 6 +- .../data/mongodb/core/MongoTemplateTests.java | 83 +++++++++++++++++++ 2 files changed, 86 insertions(+), 3 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java index 5c0a42a3b..435ab1316 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java @@ -264,8 +264,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App accessor.setProperty(idProperty, idValue); } - final ObjectPath currentPath = path.push(result, entity, idValue != null ? dbo.get(idProperty.getFieldName()) - : null); + final ObjectPath currentPath = path.push(result, entity, + idValue != null ? dbo.get(idProperty.getFieldName()) : null); // Set properties not already set in the constructor entity.doWithProperties(new PropertyHandler() { @@ -291,7 +291,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App final MongoPersistentProperty property = association.getInverse(); Object value = dbo.get(property.getFieldName()); - if (value == null) { + if (value == null || (entity.isConstructorArgument(property) && accessor.getProperty(property) != null)) { return; } 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 920c5a957..1feec6553 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 @@ -3074,6 +3074,75 @@ public class MongoTemplateTests { assertThat(contentLoaded.dbrefMessage.id, is(messageLoaded.id)); } + /** + * @see DATAMONGO-1287 + */ + @Test + public void shouldReuseAlreadyResolvedLazyLoadedDBRefWhenUsedAsPersistenceConstrcutorArgument() { + + Document docInCtor = new Document(); + docInCtor.id = "doc-in-ctor"; + template.save(docInCtor); + + DocumentWithLazyDBrefUsedInPresistenceConstructor source = new DocumentWithLazyDBrefUsedInPresistenceConstructor( + docInCtor); + + template.save(source); + + DocumentWithLazyDBrefUsedInPresistenceConstructor loaded = template.findOne(query(where("id").is(source.id)), + DocumentWithLazyDBrefUsedInPresistenceConstructor.class); + assertThat(loaded.refToDocUsedInCtor, not(instanceOf(LazyLoadingProxy.class))); + assertThat(loaded.refToDocNotUsedInCtor, nullValue()); + } + + /** + * @see DATAMONGO-1287 + */ + @Test + public void shouldNotReuseLazyLoadedDBRefWhenTypeUsedInPersistenceConstrcutorButValueRefersToAnotherProperty() { + + Document docNotUsedInCtor = new Document(); + docNotUsedInCtor.id = "doc-but-not-used-in-ctor"; + template.save(docNotUsedInCtor); + + DocumentWithLazyDBrefUsedInPresistenceConstructor source = new DocumentWithLazyDBrefUsedInPresistenceConstructor( + null); + source.refToDocNotUsedInCtor = docNotUsedInCtor; + + template.save(source); + + DocumentWithLazyDBrefUsedInPresistenceConstructor loaded = template.findOne(query(where("id").is(source.id)), + DocumentWithLazyDBrefUsedInPresistenceConstructor.class); + assertThat(loaded.refToDocNotUsedInCtor, instanceOf(LazyLoadingProxy.class)); + assertThat(loaded.refToDocUsedInCtor, nullValue()); + } + + /** + * @see DATAMONGO-1287 + */ + @Test + public void shouldRespectParamterValueWhenAttemptingToReuseLazyLoadedDBRefUsedInPersistenceConstrcutor() { + + Document docInCtor = new Document(); + docInCtor.id = "doc-in-ctor"; + template.save(docInCtor); + + Document docNotUsedInCtor = new Document(); + docNotUsedInCtor.id = "doc-but-not-used-in-ctor"; + template.save(docNotUsedInCtor); + + DocumentWithLazyDBrefUsedInPresistenceConstructor source = new DocumentWithLazyDBrefUsedInPresistenceConstructor( + docInCtor); + source.refToDocNotUsedInCtor = docNotUsedInCtor; + + template.save(source); + + DocumentWithLazyDBrefUsedInPresistenceConstructor loaded = template.findOne(query(where("id").is(source.id)), + DocumentWithLazyDBrefUsedInPresistenceConstructor.class); + assertThat(loaded.refToDocUsedInCtor, not(instanceOf(LazyLoadingProxy.class))); + assertThat(loaded.refToDocNotUsedInCtor, instanceOf(LazyLoadingProxy.class)); + } + static class DoucmentWithNamedIdField { @Id String someIdKey; @@ -3401,4 +3470,18 @@ public class MongoTemplateTests { @org.springframework.data.mongodb.core.mapping.DBRef SomeContent dbrefContent; SomeContent normalContent; } + + static class DocumentWithLazyDBrefUsedInPresistenceConstructor { + + @Id String id; + @org.springframework.data.mongodb.core.mapping.DBRef(lazy = true) Document refToDocUsedInCtor; + @org.springframework.data.mongodb.core.mapping.DBRef(lazy = true) Document refToDocNotUsedInCtor; + + @PersistenceConstructor + public DocumentWithLazyDBrefUsedInPresistenceConstructor(Document refToDocUsedInCtor) { + this.refToDocUsedInCtor = refToDocUsedInCtor; + } + + } + }