From a09183d2ebb652962323a78e0924b135feebac15 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Thu, 20 Mar 2014 09:27:37 +0100 Subject: [PATCH] DATAMONGO-880 - Minor polishing in lazy-loading area. Took the change to add @since tags to the types introduced for lazy loading. Polished JavaDoc where necessary. Removed methods solely existing for testing purposes and use reflection in tests to minimize the API being published. --- .../mongodb/core/convert/DbRefResolver.java | 8 ++- .../core/convert/DefaultDbRefResolver.java | 54 ++++++++++++------- .../core/convert/MappingMongoConverter.java | 9 ++-- .../DbRefMappingMongoConverterUnitTests.java | 6 ++- .../core/convert/LazyLoadingTestUtils.java | 7 +-- 5 files changed, 55 insertions(+), 29 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DbRefResolver.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DbRefResolver.java index 88149ed65..18ae6fa58 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DbRefResolver.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DbRefResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2013-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,10 +24,16 @@ import com.mongodb.DBRef; * Used to resolve associations annotated with {@link org.springframework.data.mongodb.core.mapping.DBRef}. * * @author Thomas Darimont + * @author Oliver Gierke + * @since 1.4 */ public interface DbRefResolver { /** + * Resolves the given {@link DBRef} into an object of the given {@link MongoPersistentProperty}'s type. The method + * might return a proxy object for the {@link DBRef} or resolve it immediately. In both cases the + * {@link DbRefResolverCallback} will be used to obtain the actual backing object. + * * @param property will never be {@literal null}. * @param dbref the {@link DBRef} to resolve. * @param callback will never be {@literal null}. diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DefaultDbRefResolver.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DefaultDbRefResolver.java index cf4974b0d..5fa81c952 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DefaultDbRefResolver.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DefaultDbRefResolver.java @@ -51,6 +51,7 @@ import com.mongodb.DBRef; * * @author Thomas Darimont * @author Oliver Gierke + * @since 1.4 */ public class DefaultDbRefResolver implements DbRefResolver { @@ -109,7 +110,7 @@ public class DefaultDbRefResolver implements DbRefResolver { * eventually resolve the value of the property. * * @param property must not be {@literal null}. - * @param dbref + * @param dbref can be {@literal null}. * @param callback must not be {@literal null}. * @return */ @@ -144,7 +145,9 @@ public class DefaultDbRefResolver implements DbRefResolver { } /** - * @param property + * Returns whether the property shall be resolved lazily. + * + * @param property must not be {@literal null}. * @return */ private boolean isLazyDbRef(MongoPersistentProperty property) { @@ -157,12 +160,12 @@ public class DefaultDbRefResolver implements DbRefResolver { * guaranteed to be performed only once. * * @author Thomas Darimont + * @author Oliver Gierke */ static class LazyLoadingInterceptor implements MethodInterceptor, org.springframework.cglib.proxy.MethodInterceptor, Serializable { - private static final Method initializeMethod; - private static final Method toDBRefMethod; + private static final Method INITIALIZE_METHOD, TO_DBREF_METHOD; private final DbRefResolverCallback callback; private final MongoPersistentProperty property; @@ -174,8 +177,8 @@ public class DefaultDbRefResolver implements DbRefResolver { static { try { - initializeMethod = LazyLoadingProxy.class.getMethod("initialize"); - toDBRefMethod = LazyLoadingProxy.class.getMethod("toDBRef"); + INITIALIZE_METHOD = LazyLoadingProxy.class.getMethod("initialize"); + TO_DBREF_METHOD = LazyLoadingProxy.class.getMethod("toDBRef"); } catch (Exception e) { throw new RuntimeException(e); } @@ -186,7 +189,7 @@ public class DefaultDbRefResolver implements DbRefResolver { * {@link PersistenceExceptionTranslator} and {@link DbRefResolverCallback}. * * @param property must not be {@literal null}. - * @param dbref + * @param dbref can be {@literal null}. * @param callback must not be {@literal null}. */ public LazyLoadingInterceptor(MongoPersistentProperty property, DBRef dbref, @@ -209,11 +212,11 @@ public class DefaultDbRefResolver implements DbRefResolver { @Override public Object invoke(MethodInvocation invocation) throws Throwable { - if (invocation.getMethod().equals(initializeMethod)) { + if (invocation.getMethod().equals(INITIALIZE_METHOD)) { return ensureResolved(); } - if (invocation.getMethod().equals(toDBRefMethod)) { + if (invocation.getMethod().equals(TO_DBREF_METHOD)) { return this.dbref; } @@ -227,17 +230,22 @@ public class DefaultDbRefResolver implements DbRefResolver { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { - if (method.equals(initializeMethod)) { + if (INITIALIZE_METHOD.equals(method)) { return ensureResolved(); } - if (method.equals(toDBRefMethod)) { + if (TO_DBREF_METHOD.equals(method)) { return this.dbref; } return ReflectionUtils.isObjectMethod(method) ? method.invoke(obj, args) : method.invoke(ensureResolved(), args); } + /** + * Will trigger the resolution if the proxy is not resolved already or return a previously resolved result. + * + * @return + */ private Object ensureResolved() { if (!resolved) { @@ -248,16 +256,28 @@ public class DefaultDbRefResolver implements DbRefResolver { return this.result; } + /** + * Callback method for serialization. + * + * @param out + * @throws IOException + */ private void writeObject(ObjectOutputStream out) throws IOException { ensureResolved(); out.writeObject(this.result); } + /** + * Callback method for deserialization. + * + * @param in + * @throws IOException + */ private void readObject(ObjectInputStream in) throws IOException { try { - this.resolved = true; // Object is guaranteed to be resolved after serializations + this.resolved = true; this.result = in.readObject(); } catch (ClassNotFoundException e) { throw new LazyLoadingException("Could not deserialize result", e); @@ -265,6 +285,8 @@ public class DefaultDbRefResolver implements DbRefResolver { } /** + * Resolves the proxy into its backing object. + * * @return */ private synchronized Object resolve() { @@ -284,14 +306,6 @@ public class DefaultDbRefResolver implements DbRefResolver { return result; } - - public boolean isResolved() { - return resolved; - } - - public Object getResult() { - return result; - } } /** 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 2d65ca9f8..00a78f1b7 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 @@ -262,11 +262,11 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App entity.doWithAssociations(new AssociationHandler() { public void doWithAssociation(Association association) { - MongoPersistentProperty inverseProp = association.getInverse(); + MongoPersistentProperty property = association.getInverse(); - Object value = dbo.get(inverseProp.getName()); + Object value = dbo.get(property.getName()); DBRef dbref = value instanceof DBRef ? (DBRef) value : null; - Object obj = dbRefResolver.resolveDbRef(inverseProp, dbref, new DbRefResolverCallback() { + Object obj = dbRefResolver.resolveDbRef(property, dbref, new DbRefResolverCallback() { @Override public Object resolve(MongoPersistentProperty property) { @@ -274,7 +274,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App } }); - wrapper.setProperty(inverseProp, obj); + wrapper.setProperty(property, obj); } }); @@ -446,6 +446,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App } dbRefObj = dbRefObj != null ? dbRefObj : createDBRef(obj, prop); + if (null != dbRefObj) { accessor.put(prop, dbRefObj); return; 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 7d626ab37..ea7408538 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 @@ -1,5 +1,5 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2013-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -50,6 +50,8 @@ import com.mongodb.DBObject; import com.mongodb.DBRef; /** + * Unit tests dor {@link DbRefMappingMongoConverterUnitTests}. + * * @author Oliver Gierke */ @RunWith(MockitoJUnitRunner.class) @@ -345,6 +347,7 @@ public class DbRefMappingMongoConverterUnitTests { } } + @SuppressWarnings("serial") static class LazyDbRefTargetWithPeristenceConstructor extends LazyDbRefTarget { boolean persistenceConstructorCalled; @@ -362,6 +365,7 @@ public class DbRefMappingMongoConverterUnitTests { } } + @SuppressWarnings("serial") static class LazyDbRefTargetWithPeristenceConstructorWithoutDefaultConstructor extends LazyDbRefTarget { boolean persistenceConstructorCalled; diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/LazyLoadingTestUtils.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/LazyLoadingTestUtils.java index 2d5b6c690..d6de71ff1 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/LazyLoadingTestUtils.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/LazyLoadingTestUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2013-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ import static org.junit.Assert.*; import org.springframework.aop.framework.Advised; import org.springframework.cglib.proxy.Factory; import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver.LazyLoadingInterceptor; +import org.springframework.test.util.ReflectionTestUtils; /** * Utility class to test proxy handling for lazy loading. @@ -39,8 +40,8 @@ public class LazyLoadingTestUtils { public static void assertProxyIsResolved(Object target, boolean expected) { LazyLoadingInterceptor interceptor = extractInterceptor(target); - assertThat(interceptor.isResolved(), is(expected)); - assertThat(interceptor.getResult(), is(expected ? notNullValue() : nullValue())); + assertThat(ReflectionTestUtils.getField(interceptor, "resolved"), is((Object) expected)); + assertThat(ReflectionTestUtils.getField(interceptor, "result"), is(expected ? notNullValue() : nullValue())); } private static LazyLoadingInterceptor extractInterceptor(Object proxy) {