From 35971947424d19bb1130f15bbd8d90ab4b22dc1c Mon Sep 17 00:00:00 2001 From: Thomas Darimont Date: Wed, 13 Aug 2014 13:46:05 +0200 Subject: [PATCH] DATAMONGO-1012 - Improved identifier initialization on DBRef proxies. Identifier initalization is now only triggered if field access is used. Before that the id initialization would've resolved the proxy eagerly as the getter access performed by the BeanWrapper would've been intercepted by the proxy and is indistinguishable from a normal method call. This would've rendered the entire use case to create proxies ad absurdum. Added test case to check for non-initialization in the property access scenario. --- .../convert/DefaultDbRefProxyHandler.java | 8 +-- .../DbRefMappingMongoConverterUnitTests.java | 49 ++++++++++++++++++- 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DefaultDbRefProxyHandler.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DefaultDbRefProxyHandler.java index d3f753160..a9bbc98f7 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DefaultDbRefProxyHandler.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DefaultDbRefProxyHandler.java @@ -62,14 +62,14 @@ class DefaultDbRefProxyHandler implements DbRefProxyHandler { MongoPersistentEntity persistentEntity = mappingContext.getPersistentEntity(property); MongoPersistentProperty idProperty = persistentEntity.getIdProperty(); - - if (idProperty.usePropertyAccess()) { + + if(idProperty.usePropertyAccess()) { return proxy; } - + SpELExpressionEvaluator evaluator = new DefaultSpELExpressionEvaluator(proxy, spELContext); BeanWrapper proxyWrapper = BeanWrapper.create(proxy, null); - + DBObject object = new BasicDBObject(idProperty.getFieldName(), source.getId()); ObjectPath objectPath = ObjectPath.ROOT.push(proxy, persistentEntity, null); proxyWrapper.setProperty(idProperty, resolver.getValueInternal(idProperty, object, evaluator, objectPath)); diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/DbRefMappingMongoConverterUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/DbRefMappingMongoConverterUnitTests.java index b865c9688..73252ee50 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/DbRefMappingMongoConverterUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/DbRefMappingMongoConverterUnitTests.java @@ -36,6 +36,8 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.data.annotation.AccessType; +import org.springframework.data.annotation.AccessType.Type; import org.springframework.data.annotation.Id; import org.springframework.data.annotation.PersistenceConstructor; import org.springframework.data.mapping.PropertyPath; @@ -46,6 +48,7 @@ import org.springframework.data.mongodb.core.convert.MappingMongoConverterUnitTe import org.springframework.data.mongodb.core.mapping.MongoMappingContext; import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; +import org.springframework.test.util.ReflectionTestUtils; import org.springframework.util.SerializationUtils; import com.mongodb.BasicDBObject; @@ -494,13 +497,17 @@ public class DbRefMappingMongoConverterUnitTests { assertThat(found.nested.reference, is(found)); } + /** + * @see DATAMONGO-1012 + */ @Test - public void testname() { + public void shouldEagerlyResolveIdPropertyWithFieldAccess() { MongoPersistentEntity entity = mappingContext.getPersistentEntity(ClassWithLazyDbRefs.class); MongoPersistentProperty property = entity.getPersistentProperty("dbRefToConcreteType"); - Object dbRef = converter.toDBRef(new LazyDbRefTarget(new ObjectId().toString()), property); + String idValue = new ObjectId().toString(); + DBRef dbRef = converter.toDBRef(new LazyDbRefTarget(idValue), property); DBObject object = new BasicDBObject("dbRefToConcreteType", dbRef); @@ -510,6 +517,28 @@ public class DbRefMappingMongoConverterUnitTests { MongoPersistentProperty idProperty = mappingContext.getPersistentEntity(LazyDbRefTarget.class).getIdProperty(); assertThat(wrapper.getProperty(idProperty), is(notNullValue())); + assertProxyIsResolved(result.dbRefToConcreteType, false); + } + + /** + * @see DATAMONGO-1012 + */ + @Test + public void shouldNotEagerlyResolveIdPropertyWithPropertyAccess() { + + MongoPersistentEntity entity = mappingContext.getPersistentEntity(ClassWithLazyDbRefs.class); + MongoPersistentProperty property = entity.getPersistentProperty("dbRefToConcreteTypeWithPropertyAccess"); + + String idValue = new ObjectId().toString(); + DBRef dbRef = converter.toDBRef(new LazyDbRefTargetPropertyAccess(idValue), property); + + DBObject object = new BasicDBObject("dbRefToConcreteTypeWithPropertyAccess", dbRef); + + ClassWithLazyDbRefs result = converter.read(ClassWithLazyDbRefs.class, object); + + LazyDbRefTargetPropertyAccess proxy = result.dbRefToConcreteTypeWithPropertyAccess; + assertThat(ReflectionTestUtils.getField(proxy, "id"), is(nullValue())); + assertProxyIsResolved(proxy, false); } private Object transport(Object result) { @@ -534,6 +563,7 @@ public class DbRefMappingMongoConverterUnitTests { @org.springframework.data.mongodb.core.mapping.DBRef(lazy = true) List dbRefToInterface; @org.springframework.data.mongodb.core.mapping.DBRef(lazy = true) ArrayList dbRefToConcreteCollection; @org.springframework.data.mongodb.core.mapping.DBRef(lazy = true) LazyDbRefTarget dbRefToConcreteType; + @org.springframework.data.mongodb.core.mapping.DBRef(lazy = true) LazyDbRefTargetPropertyAccess dbRefToConcreteTypeWithPropertyAccess; @org.springframework.data.mongodb.core.mapping.DBRef(lazy = true) LazyDbRefTargetWithPeristenceConstructor dbRefToConcreteTypeWithPersistenceConstructor; @org.springframework.data.mongodb.core.mapping.DBRef(lazy = true) LazyDbRefTargetWithPeristenceConstructorWithoutDefaultConstructor dbRefToConcreteTypeWithPersistenceConstructorWithoutDefaultConstructor; } @@ -574,6 +604,21 @@ public class DbRefMappingMongoConverterUnitTests { } } + static class LazyDbRefTargetPropertyAccess implements Serializable { + + private static final long serialVersionUID = 1L; + + @Id @AccessType(Type.PROPERTY) String id; + + public LazyDbRefTargetPropertyAccess(String id) { + this.id = id; + } + + public String getId() { + return id; + } + } + @SuppressWarnings("serial") static class LazyDbRefTargetWithPeristenceConstructor extends LazyDbRefTarget {