Browse Source

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.
pull/131/merge
Oliver Gierke 12 years ago
parent
commit
a09183d2eb
  1. 8
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DbRefResolver.java
  2. 54
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DefaultDbRefResolver.java
  3. 9
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java
  4. 6
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/DbRefMappingMongoConverterUnitTests.java
  5. 7
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/LazyLoadingTestUtils.java

8
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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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}. * Used to resolve associations annotated with {@link org.springframework.data.mongodb.core.mapping.DBRef}.
* *
* @author Thomas Darimont * @author Thomas Darimont
* @author Oliver Gierke
* @since 1.4
*/ */
public interface DbRefResolver { 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 property will never be {@literal null}.
* @param dbref the {@link DBRef} to resolve. * @param dbref the {@link DBRef} to resolve.
* @param callback will never be {@literal null}. * @param callback will never be {@literal null}.

54
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 Thomas Darimont
* @author Oliver Gierke * @author Oliver Gierke
* @since 1.4
*/ */
public class DefaultDbRefResolver implements DbRefResolver { public class DefaultDbRefResolver implements DbRefResolver {
@ -109,7 +110,7 @@ public class DefaultDbRefResolver implements DbRefResolver {
* eventually resolve the value of the property. * eventually resolve the value of the property.
* *
* @param property must not be {@literal null}. * @param property must not be {@literal null}.
* @param dbref * @param dbref can be {@literal null}.
* @param callback must not be {@literal null}. * @param callback must not be {@literal null}.
* @return * @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 * @return
*/ */
private boolean isLazyDbRef(MongoPersistentProperty property) { private boolean isLazyDbRef(MongoPersistentProperty property) {
@ -157,12 +160,12 @@ public class DefaultDbRefResolver implements DbRefResolver {
* guaranteed to be performed only once. * guaranteed to be performed only once.
* *
* @author Thomas Darimont * @author Thomas Darimont
* @author Oliver Gierke
*/ */
static class LazyLoadingInterceptor implements MethodInterceptor, org.springframework.cglib.proxy.MethodInterceptor, static class LazyLoadingInterceptor implements MethodInterceptor, org.springframework.cglib.proxy.MethodInterceptor,
Serializable { Serializable {
private static final Method initializeMethod; private static final Method INITIALIZE_METHOD, TO_DBREF_METHOD;
private static final Method toDBRefMethod;
private final DbRefResolverCallback callback; private final DbRefResolverCallback callback;
private final MongoPersistentProperty property; private final MongoPersistentProperty property;
@ -174,8 +177,8 @@ public class DefaultDbRefResolver implements DbRefResolver {
static { static {
try { try {
initializeMethod = LazyLoadingProxy.class.getMethod("initialize"); INITIALIZE_METHOD = LazyLoadingProxy.class.getMethod("initialize");
toDBRefMethod = LazyLoadingProxy.class.getMethod("toDBRef"); TO_DBREF_METHOD = LazyLoadingProxy.class.getMethod("toDBRef");
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@ -186,7 +189,7 @@ public class DefaultDbRefResolver implements DbRefResolver {
* {@link PersistenceExceptionTranslator} and {@link DbRefResolverCallback}. * {@link PersistenceExceptionTranslator} and {@link DbRefResolverCallback}.
* *
* @param property must not be {@literal null}. * @param property must not be {@literal null}.
* @param dbref * @param dbref can be {@literal null}.
* @param callback must not be {@literal null}. * @param callback must not be {@literal null}.
*/ */
public LazyLoadingInterceptor(MongoPersistentProperty property, DBRef dbref, public LazyLoadingInterceptor(MongoPersistentProperty property, DBRef dbref,
@ -209,11 +212,11 @@ public class DefaultDbRefResolver implements DbRefResolver {
@Override @Override
public Object invoke(MethodInvocation invocation) throws Throwable { public Object invoke(MethodInvocation invocation) throws Throwable {
if (invocation.getMethod().equals(initializeMethod)) { if (invocation.getMethod().equals(INITIALIZE_METHOD)) {
return ensureResolved(); return ensureResolved();
} }
if (invocation.getMethod().equals(toDBRefMethod)) { if (invocation.getMethod().equals(TO_DBREF_METHOD)) {
return this.dbref; return this.dbref;
} }
@ -227,17 +230,22 @@ public class DefaultDbRefResolver implements DbRefResolver {
@Override @Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
if (method.equals(initializeMethod)) { if (INITIALIZE_METHOD.equals(method)) {
return ensureResolved(); return ensureResolved();
} }
if (method.equals(toDBRefMethod)) { if (TO_DBREF_METHOD.equals(method)) {
return this.dbref; return this.dbref;
} }
return ReflectionUtils.isObjectMethod(method) ? method.invoke(obj, args) : method.invoke(ensureResolved(), args); 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() { private Object ensureResolved() {
if (!resolved) { if (!resolved) {
@ -248,16 +256,28 @@ public class DefaultDbRefResolver implements DbRefResolver {
return this.result; return this.result;
} }
/**
* Callback method for serialization.
*
* @param out
* @throws IOException
*/
private void writeObject(ObjectOutputStream out) throws IOException { private void writeObject(ObjectOutputStream out) throws IOException {
ensureResolved(); ensureResolved();
out.writeObject(this.result); out.writeObject(this.result);
} }
/**
* Callback method for deserialization.
*
* @param in
* @throws IOException
*/
private void readObject(ObjectInputStream in) throws IOException { private void readObject(ObjectInputStream in) throws IOException {
try { try {
this.resolved = true; // Object is guaranteed to be resolved after serializations this.resolved = true;
this.result = in.readObject(); this.result = in.readObject();
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
throw new LazyLoadingException("Could not deserialize result", 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 * @return
*/ */
private synchronized Object resolve() { private synchronized Object resolve() {
@ -284,14 +306,6 @@ public class DefaultDbRefResolver implements DbRefResolver {
return result; return result;
} }
public boolean isResolved() {
return resolved;
}
public Object getResult() {
return result;
}
} }
/** /**

9
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<MongoPersistentProperty>() { entity.doWithAssociations(new AssociationHandler<MongoPersistentProperty>() {
public void doWithAssociation(Association<MongoPersistentProperty> association) { public void doWithAssociation(Association<MongoPersistentProperty> 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; 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 @Override
public Object resolve(MongoPersistentProperty property) { 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); dbRefObj = dbRefObj != null ? dbRefObj : createDBRef(obj, prop);
if (null != dbRefObj) { if (null != dbRefObj) {
accessor.put(prop, dbRefObj); accessor.put(prop, dbRefObj);
return; return;

6
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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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; import com.mongodb.DBRef;
/** /**
* Unit tests dor {@link DbRefMappingMongoConverterUnitTests}.
*
* @author Oliver Gierke * @author Oliver Gierke
*/ */
@RunWith(MockitoJUnitRunner.class) @RunWith(MockitoJUnitRunner.class)
@ -345,6 +347,7 @@ public class DbRefMappingMongoConverterUnitTests {
} }
} }
@SuppressWarnings("serial")
static class LazyDbRefTargetWithPeristenceConstructor extends LazyDbRefTarget { static class LazyDbRefTargetWithPeristenceConstructor extends LazyDbRefTarget {
boolean persistenceConstructorCalled; boolean persistenceConstructorCalled;
@ -362,6 +365,7 @@ public class DbRefMappingMongoConverterUnitTests {
} }
} }
@SuppressWarnings("serial")
static class LazyDbRefTargetWithPeristenceConstructorWithoutDefaultConstructor extends LazyDbRefTarget { static class LazyDbRefTargetWithPeristenceConstructorWithoutDefaultConstructor extends LazyDbRefTarget {
boolean persistenceConstructorCalled; boolean persistenceConstructorCalled;

7
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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.aop.framework.Advised;
import org.springframework.cglib.proxy.Factory; import org.springframework.cglib.proxy.Factory;
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver.LazyLoadingInterceptor; import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver.LazyLoadingInterceptor;
import org.springframework.test.util.ReflectionTestUtils;
/** /**
* Utility class to test proxy handling for lazy loading. * Utility class to test proxy handling for lazy loading.
@ -39,8 +40,8 @@ public class LazyLoadingTestUtils {
public static void assertProxyIsResolved(Object target, boolean expected) { public static void assertProxyIsResolved(Object target, boolean expected) {
LazyLoadingInterceptor interceptor = extractInterceptor(target); LazyLoadingInterceptor interceptor = extractInterceptor(target);
assertThat(interceptor.isResolved(), is(expected)); assertThat(ReflectionTestUtils.getField(interceptor, "resolved"), is((Object) expected));
assertThat(interceptor.getResult(), is(expected ? notNullValue() : nullValue())); assertThat(ReflectionTestUtils.getField(interceptor, "result"), is(expected ? notNullValue() : nullValue()));
} }
private static LazyLoadingInterceptor extractInterceptor(Object proxy) { private static LazyLoadingInterceptor extractInterceptor(Object proxy) {

Loading…
Cancel
Save